summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools')
-rw-r--r--contrib/llvm/tools/bugpoint/BugDriver.cpp4
-rw-r--r--contrib/llvm/tools/bugpoint/CMakeLists.txt14
-rw-r--r--contrib/llvm/tools/bugpoint/CrashDebugger.cpp11
-rw-r--r--contrib/llvm/tools/bugpoint/ExecutionDriver.cpp50
-rw-r--r--contrib/llvm/tools/bugpoint/ExtractFunction.cpp62
-rw-r--r--contrib/llvm/tools/bugpoint/Makefile16
-rw-r--r--contrib/llvm/tools/bugpoint/Miscompilation.cpp3
-rw-r--r--contrib/llvm/tools/bugpoint/OptimizerDriver.cpp12
-rw-r--r--contrib/llvm/tools/bugpoint/ToolRunner.cpp93
-rw-r--r--contrib/llvm/tools/bugpoint/ToolRunner.h1
-rw-r--r--contrib/llvm/tools/bugpoint/bugpoint.cpp1
-rw-r--r--contrib/llvm/tools/clang/LICENSE.TXT2
-rw-r--r--contrib/llvm/tools/clang/include/clang-c/Index.h952
-rw-r--r--contrib/llvm/tools/clang/include/clang/ARCMigrate/ARCMT.h18
-rw-r--r--contrib/llvm/tools/clang/include/clang/ARCMigrate/ARCMTActions.h26
-rw-r--r--contrib/llvm/tools/clang/include/clang/ARCMigrate/FileRemapper.h11
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/APValue.h269
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/ASTConsumer.h24
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/ASTContext.h203
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/ASTDiagnostic.h4
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/ASTImporter.h6
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/ASTMutationListener.h17
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/Attr.h18
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/BuiltinTypes.def224
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/CanonicalType.h9
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/Decl.h852
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/DeclBase.h354
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h668
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/DeclFriend.h6
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/DeclLookups.h84
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h784
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h529
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/DeclVisitor.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h14
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/DependentDiagnostic.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/Expr.h1157
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h1556
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/ExprObjC.h517
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h46
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/LambdaMangleContext.h36
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/Mangle.h4
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/NSAPI.h152
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/NestedNameSpecifier.h103
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/OperationKinds.h30
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/PrettyPrinter.h6
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/RecordLayout.h20
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h270
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h32
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/Stmt.h223
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/StmtCXX.h96
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/StmtObjC.h15
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/StmtVisitor.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h45
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/Type.h710
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h142
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/TypeVisitor.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/UsuallyTinyPtrVector.h114
-rw-r--r--contrib/llvm/tools/clang/include/clang/AST/VTableBuilder.h82
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Dominators.h212
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/Analyses/FormatString.h143
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/Analyses/LiveVariables.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/Analyses/PostOrderCFGView.h111
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ReachableCode.h5
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafety.h14
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/Analyses/UninitializedValues.h12
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h207
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/AnalysisDiagnostic.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/CFG.h188
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/CallGraph.h257
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/DomainSpecific/CocoaConventions.h12
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/ProgramPoint.h113
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/Support/SaveAndRestore.h47
-rw-r--r--contrib/llvm/tools/clang/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h3
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/AllDiagnostics.h39
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Attr.td42
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Builtins.def109
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/BuiltinsHexagon.def689
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def271
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/ConvertUTF.h14
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td4
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h276
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td9
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td98
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticAnalysisKinds.td3
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td13
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td24
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td93
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td127
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h65
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td175
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td246
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td1272
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td60
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/ExpressionTraits.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/FileManager.h17
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/FileSystemStatCache.h4
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h79
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/LLVM.h22
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Lambda.h38
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def20
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h38
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Linkage.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Module.h284
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/OnDiskHashTable.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/PartialDiagnostic.h137
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h4
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h206
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/StmtNodes.td11
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h49
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h47
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def29
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Basic/Version.h24
-rw-r--r--contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenAction.h14
-rw-r--r--contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h1
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/Action.h24
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/ArgList.h12
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/CC1AsOptions.td9
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td131
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/Compilation.h15
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/Driver.h34
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/DriverDiagnostic.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/HostInfo.h94
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/Job.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/ObjCRuntime.h5
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/OptTable.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/Options.td157
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/Tool.h1
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h37
-rw-r--r--contrib/llvm/tools/clang/include/clang/Driver/Types.def2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Edit/Commit.h140
-rw-r--r--contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h87
-rw-r--r--contrib/llvm/tools/clang/include/clang/Edit/EditsReceiver.h35
-rw-r--r--contrib/llvm/tools/clang/include/clang/Edit/FileOffset.h65
-rw-r--r--contrib/llvm/tools/clang/include/clang/Edit/Rewriters.h33
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h185
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/Analyses.def17
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/AnalyzerOptions.h29
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/ChainedIncludesSource.h (renamed from contrib/llvm/tools/clang/include/clang/Serialization/ChainedIncludesSource.h)4
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h26
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h78
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h47
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/DependencyOutputOptions.h5
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/DiagnosticOptions.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/DiagnosticRenderer.h149
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/FrontendAction.h57
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h50
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/FrontendDiagnostic.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h63
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h6
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def23
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/LayoutOverrideSource.h61
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/MigratorOptions.h31
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/MultiplexConsumer.h13
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/PreprocessorOptions.h20
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h62
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnostic.h120
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnosticPrinter.h36
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/Utils.h23
-rw-r--r--contrib/llvm/tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Index/ASTLocation.h17
-rw-r--r--contrib/llvm/tools/clang/include/clang/Index/GlobalCallGraph.h (renamed from contrib/llvm/tools/clang/include/clang/Index/CallGraph.h)33
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/DirectoryLookup.h21
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/ExternalPreprocessorSource.h3
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h229
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/LexDiagnostic.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/Lexer.h75
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/LiteralSupport.h54
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h25
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h32
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/ModuleMap.h237
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h89
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h111
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h210
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h1
-rw-r--r--contrib/llvm/tools/clang/include/clang/Lex/Token.h6
-rw-r--r--contrib/llvm/tools/clang/include/clang/Parse/ParseAST.h6
-rw-r--r--contrib/llvm/tools/clang/include/clang/Parse/ParseDiagnostic.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Parse/Parser.h581
-rw-r--r--contrib/llvm/tools/clang/include/clang/Rewrite/ASTConsumers.h5
-rw-r--r--contrib/llvm/tools/clang/include/clang/Rewrite/FixItRewriter.h28
-rw-r--r--contrib/llvm/tools/clang/include/clang/Rewrite/FrontendActions.h15
-rw-r--r--contrib/llvm/tools/clang/include/clang/Rewrite/TokenRewriter.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h149
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteConsumer.h469
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h153
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/DelayedDiagnostic.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/ExternalSemaSource.h5
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/IdentifierResolver.h33
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/Initialization.h252
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/LocInfoType.h12
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/Lookup.h55
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/MultiInitializer.h72
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/Overload.h145
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/ParsedTemplate.h6
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/PrettyDeclStackTrace.h5
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/Scope.h35
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h274
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/Sema.h1679
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/SemaConsumer.h1
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/SemaDiagnostic.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/SemaFixItUtils.h2
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/Template.h64
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/TemplateDeduction.h21
-rw-r--r--contrib/llvm/tools/clang/include/clang/Sema/TypoCorrection.h148
-rw-r--r--contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h215
-rw-r--r--contrib/llvm/tools/clang/include/clang/Serialization/ASTDeserializationListener.h6
-rw-r--r--contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h544
-rw-r--r--contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h235
-rw-r--r--contrib/llvm/tools/clang/include/clang/Serialization/ContinuousRangeMap.h10
-rw-r--r--contrib/llvm/tools/clang/include/clang/Serialization/Module.h229
-rw-r--r--contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h30
-rw-r--r--contrib/llvm/tools/clang/include/clang/Serialization/SerializationDiagnostic.h28
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/CommonBugCategories.h24
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h197
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h80
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h1
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h394
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Checker.h44
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h83
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerRegistry.h4
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h4
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h95
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h7
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h228
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h27
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h545
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h66
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h84
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h210
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h80
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h107
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h204
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h244
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h260
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h19
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h43
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h102
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h63
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h63
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h51
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h173
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h40
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h27
-rw-r--r--contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h1
-rw-r--r--contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabase.h164
-rw-r--r--contrib/llvm/tools/clang/include/clang/Tooling/Tooling.h213
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/ARCMT.cpp165
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/ARCMTActions.cpp17
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/FileRemapper.cpp44
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/Internals.h19
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp226
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/TransARCAssign.cpp3
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/TransAutoreleasePool.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp66
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp43
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/TransGCAttrs.cpp358
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/TransGCCalls.cpp84
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp328
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp112
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp30
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/TransUnusedInitDelegate.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp75
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp33
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.cpp344
-rw-r--r--contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.h118
-rw-r--r--contrib/llvm/tools/clang/lib/AST/APValue.cpp573
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ASTConsumer.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ASTContext.cpp516
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp26
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp773
-rw-r--r--contrib/llvm/tools/clang/lib/AST/AttrImpl.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp15
-rw-r--r--contrib/llvm/tools/clang/lib/AST/Decl.cpp919
-rw-r--r--contrib/llvm/tools/clang/lib/AST/DeclBase.cpp418
-rw-r--r--contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp467
-rw-r--r--contrib/llvm/tools/clang/lib/AST/DeclFriend.cpp7
-rw-r--r--contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp442
-rw-r--r--contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp91
-rw-r--r--contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp198
-rw-r--r--contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp16
-rw-r--r--contrib/llvm/tools/clang/lib/AST/DumpXML.cpp50
-rw-r--r--contrib/llvm/tools/clang/lib/AST/Expr.cpp1003
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp536
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp90
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp5717
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp387
-rw-r--r--contrib/llvm/tools/clang/lib/AST/LambdaMangleContext.cpp30
-rw-r--r--contrib/llvm/tools/clang/lib/AST/Mangle.cpp12
-rw-r--r--contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp33
-rw-r--r--contrib/llvm/tools/clang/lib/AST/NSAPI.cpp312
-rw-r--r--contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp28
-rw-r--r--contrib/llvm/tools/clang/lib/AST/ParentMap.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/AST/RecordLayout.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp766
-rw-r--r--contrib/llvm/tools/clang/lib/AST/Stmt.cpp102
-rw-r--r--contrib/llvm/tools/clang/lib/AST/StmtDumper.cpp69
-rw-r--r--contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp412
-rw-r--r--contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp99
-rw-r--r--contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp114
-rw-r--r--contrib/llvm/tools/clang/lib/AST/TemplateName.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/AST/Type.cpp277
-rw-r--r--contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp113
-rw-r--r--contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp109
-rw-r--r--contrib/llvm/tools/clang/lib/AST/VTableBuilder.cpp17
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp (renamed from contrib/llvm/tools/clang/lib/Analysis/AnalysisContext.cpp)137
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/CFG.cpp405
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp184
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp49
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/Dominators.cpp14
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/FormatString.cpp259
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/FormatStringParsing.h6
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp171
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/PostOrderCFGView.cpp49
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp177
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/ProgramPoint.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/PseudoConstantAnalysis.cpp17
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp290
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp1533
-rw-r--r--contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp10
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/Builtins.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/ConvertUTF.c143
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp126
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp229
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/FileManager.cpp27
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/FileSystemStatCache.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp43
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/LangOptions.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/Module.cpp274
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp144
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp5
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/Targets.cpp956
-rw-r--r--contrib/llvm/tools/clang/lib/Basic/Version.cpp58
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/ABIInfo.h21
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp143
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp387
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.h47
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp2692
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp29
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp43
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h34
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp621
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGCall.h154
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp362
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp74
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp946
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h42
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp243
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp220
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp145
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGException.h56
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp1017
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp580
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp296
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp66
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp879
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp335
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp836
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp296
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp851
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp74
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h28
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGRTTI.cpp59
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp183
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp62
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGTemporaries.cpp49
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp21
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp40
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGValue.h84
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp107
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp180
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h407
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp617
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h115
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h4
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp44
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h109
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp334
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp7
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp17
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp882
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h5
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Action.cpp31
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Arg.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ArgList.cpp30
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/CC1AsOptions.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/CC1Options.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Compilation.cpp8
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Driver.cpp370
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/HostInfo.cpp731
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Job.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Option.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp187
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp1513
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/ToolChains.h337
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Tools.cpp1594
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Tools.h97
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/Types.cpp1
-rw-r--r--contrib/llvm/tools/clang/lib/Driver/WindowsToolChain.cpp368
-rw-r--r--contrib/llvm/tools/clang/lib/Edit/Commit.cpp345
-rw-r--r--contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp329
-rw-r--r--contrib/llvm/tools/clang/lib/Edit/RewriteObjCFoundationAPI.cpp587
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp3
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp13
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp746
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ChainedDiagnosticConsumer.cpp14
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp (renamed from contrib/llvm/tools/clang/lib/Serialization/ChainedIncludesSource.cpp)40
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp813
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp818
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp17
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp64
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/DependencyGraph.cpp140
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp386
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp137
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp314
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp5
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp46
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp128
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp3
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/LayoutOverrideSource.cpp206
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp8
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp50
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp8
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp592
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp881
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp1148
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp38
-rw-r--r--contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp190
-rw-r--r--contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp43
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/avx2intrin.h961
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/avxintrin.h331
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/bmi2intrin.h75
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/bmiintrin.h115
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/cpuid.h33
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/emmintrin.h56
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/float.h11
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/fma4intrin.h231
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/immintrin.h18
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/lzcntintrin.h55
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/mm3dnow.h2
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/module.map108
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/popcntintrin.h45
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/smmintrin.h127
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/tgmath.h23
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/tmmintrin.h11
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/unwind.h124
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/wmmintrin.h2
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/x86intrin.h26
-rw-r--r--contrib/llvm/tools/clang/lib/Headers/xmmintrin.h21
-rw-r--r--contrib/llvm/tools/clang/lib/Index/ASTLocation.cpp12
-rw-r--r--contrib/llvm/tools/clang/lib/Index/Analyzer.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/Index/GlobalCallGraph.cpp (renamed from contrib/llvm/tools/clang/lib/Index/CallGraph.cpp)10
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/HeaderMap.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp516
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/Lexer.cpp438
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp464
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp9
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp5
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/ModuleMap.cpp1437
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/PPCaching.cpp22
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/PPCallbacks.cpp14
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp354
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp22
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp88
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp134
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/Pragma.cpp211
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp265
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp149
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/TokenConcatenation.cpp49
-rw-r--r--contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp12
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp35
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp120
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp1544
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp685
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp365
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp610
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp179
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp526
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp118
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParsePragma.h10
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp252
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp184
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp331
-rw-r--r--contrib/llvm/tools/clang/lib/Parse/Parser.cpp454
-rw-r--r--contrib/llvm/tools/clang/lib/Rewrite/FixItRewriter.cpp115
-rw-r--r--contrib/llvm/tools/clang/lib/Rewrite/FrontendActions.cpp75
-rw-r--r--contrib/llvm/tools/clang/lib/Rewrite/HTMLPrint.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp10
-rw-r--r--contrib/llvm/tools/clang/lib/Rewrite/RewriteMacros.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/Rewrite/RewriteModernObjC.cpp7275
-rw-r--r--contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp3197
-rw-r--r--contrib/llvm/tools/clang/lib/Rewrite/RewriteTest.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Rewrite/Rewriter.cpp3
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp250
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp133
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp186
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp33
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp158
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp124
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/MultiInitializer.cpp92
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/Scope.cpp28
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/Sema.cpp269
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp326
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp54
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp167
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp271
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp2110
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp1135
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaConsumer.cpp14
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp2332
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp267
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp3141
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp779
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp21
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp3464
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp1341
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp346
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp1491
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaFixItUtils.cpp44
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp2136
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp820
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp825
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp382
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp2109
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp1351
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp532
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp1265
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp763
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp305
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp654
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp117
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaType.cpp837
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/TreeTransform.h1141
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp3
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h1
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp1589
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp1529
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h25
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp377
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp929
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp435
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp295
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp13
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/Module.cpp18
-rw-r--r--contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp51
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp11
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp74
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp9
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp63
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp13
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp70
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp157
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp21
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp481
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp191
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp128
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp6
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp21
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp232
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp9
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp233
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td148
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp22
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckers.h2
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CommonBugCategories.cpp18
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp56
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp70
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp60
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp45
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp9
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp740
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp34
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/InterCheckerAPI.h22
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp46
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp15
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp229
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp34
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp1341
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp7
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp211
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp31
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp14
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp96
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp21
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp174
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp159
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp82
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp11
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp11
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp44
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp900
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp10
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp7
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp64
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp109
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp62
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp37
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp20
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp20
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp7
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp8
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp204
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp34
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp87
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp241
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AggExprVisitor.cpp69
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp38
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp66
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp750
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp237
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Checker.cpp9
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp76
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp174
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp5
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp592
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp147
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp174
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp1215
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp611
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp237
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp357
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp92
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/FunctionSummary.cpp38
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp127
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp170
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp118
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp466
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp298
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp350
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp64
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp388
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp152
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp89
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp178
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.h36
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp341
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp46
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SubEngine.cpp14
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp128
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp31
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp414
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp230
-rw-r--r--contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp296
-rw-r--r--contrib/llvm/tools/clang/tools/driver/cc1_main.cpp22
-rw-r--r--contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp80
-rw-r--r--contrib/llvm/tools/clang/tools/driver/driver.cpp38
-rw-r--r--contrib/llvm/tools/clang/utils/TableGen/CMakeLists.txt12
-rw-r--r--contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp318
-rw-r--r--contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.h39
-rw-r--r--contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp113
-rw-r--r--contrib/llvm/tools/clang/utils/TableGen/Makefile19
-rw-r--r--contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.cpp91
-rw-r--r--contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.h34
-rw-r--r--contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp26
-rw-r--r--contrib/llvm/tools/llc/CMakeLists.txt5
-rw-r--r--contrib/llvm/tools/llc/Makefile21
-rw-r--r--contrib/llvm/tools/llc/llc.cpp206
-rw-r--r--contrib/llvm/tools/lli/CMakeLists.txt5
-rw-r--r--contrib/llvm/tools/lli/Makefile15
-rw-r--r--contrib/llvm/tools/lli/lli.cpp38
-rw-r--r--contrib/llvm/tools/llvm-ar/CMakeLists.txt8
-rw-r--r--contrib/llvm/tools/llvm-ar/Makefile25
-rw-r--r--contrib/llvm/tools/llvm-as/CMakeLists.txt6
-rw-r--r--contrib/llvm/tools/llvm-as/Makefile17
-rw-r--r--contrib/llvm/tools/llvm-as/llvm-as.cpp2
-rw-r--r--contrib/llvm/tools/llvm-bcanalyzer/CMakeLists.txt6
-rw-r--r--contrib/llvm/tools/llvm-bcanalyzer/Makefile17
-rw-r--r--contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp123
-rw-r--r--contrib/llvm/tools/llvm-diff/CMakeLists.txt8
-rw-r--r--contrib/llvm/tools/llvm-diff/DiffConsumer.cpp6
-rw-r--r--contrib/llvm/tools/llvm-diff/DiffConsumer.h1
-rw-r--r--contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp18
-rw-r--r--contrib/llvm/tools/llvm-diff/DifferenceEngine.h4
-rw-r--r--contrib/llvm/tools/llvm-diff/Makefile17
-rw-r--r--contrib/llvm/tools/llvm-diff/llvm-diff.cpp2
-rw-r--r--contrib/llvm/tools/llvm-dis/CMakeLists.txt6
-rw-r--r--contrib/llvm/tools/llvm-dis/Makefile17
-rw-r--r--contrib/llvm/tools/llvm-dis/llvm-dis.cpp19
-rw-r--r--contrib/llvm/tools/llvm-extract/CMakeLists.txt5
-rw-r--r--contrib/llvm/tools/llvm-extract/Makefile18
-rw-r--r--contrib/llvm/tools/llvm-extract/llvm-extract.cpp12
-rw-r--r--contrib/llvm/tools/llvm-ld/CMakeLists.txt8
-rw-r--r--contrib/llvm/tools/llvm-ld/Makefile15
-rw-r--r--contrib/llvm/tools/llvm-ld/llvm-ld.cpp4
-rw-r--r--contrib/llvm/tools/llvm-link/CMakeLists.txt5
-rw-r--r--contrib/llvm/tools/llvm-link/Makefile17
-rw-r--r--contrib/llvm/tools/llvm-link/llvm-link.cpp2
-rw-r--r--contrib/llvm/tools/llvm-mc/CMakeLists.txt6
-rw-r--r--contrib/llvm/tools/llvm-mc/Disassembler.cpp36
-rw-r--r--contrib/llvm/tools/llvm-mc/Makefile24
-rw-r--r--contrib/llvm/tools/llvm-mc/llvm-mc.cpp49
-rw-r--r--contrib/llvm/tools/llvm-nm/CMakeLists.txt5
-rw-r--r--contrib/llvm/tools/llvm-nm/Makefile17
-rw-r--r--contrib/llvm/tools/llvm-nm/llvm-nm.cpp102
-rw-r--r--contrib/llvm/tools/llvm-objdump/CMakeLists.txt14
-rw-r--r--contrib/llvm/tools/llvm-objdump/MachODump.cpp404
-rw-r--r--contrib/llvm/tools/llvm-objdump/Makefile18
-rw-r--r--contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp228
-rw-r--r--contrib/llvm/tools/llvm-objdump/llvm-objdump.h2
-rw-r--r--contrib/llvm/tools/llvm-prof/CMakeLists.txt5
-rw-r--r--contrib/llvm/tools/llvm-prof/Makefile17
-rw-r--r--contrib/llvm/tools/llvm-prof/llvm-prof.cpp18
-rw-r--r--contrib/llvm/tools/llvm-ranlib/CMakeLists.txt6
-rw-r--r--contrib/llvm/tools/llvm-ranlib/Makefile18
-rw-r--r--contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp218
-rw-r--r--contrib/llvm/tools/llvm-rtdyld/CMakeLists.txt5
-rw-r--r--contrib/llvm/tools/llvm-rtdyld/Makefile23
-rw-r--r--contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp31
-rw-r--r--contrib/llvm/tools/llvm-stress/llvm-stress.cpp702
-rw-r--r--contrib/llvm/tools/llvm-stub/CMakeLists.txt3
-rw-r--r--contrib/llvm/tools/llvm-stub/Makefile13
-rw-r--r--contrib/llvm/tools/macho-dump/CMakeLists.txt5
-rw-r--r--contrib/llvm/tools/macho-dump/Makefile23
-rw-r--r--contrib/llvm/tools/opt/CMakeLists.txt8
-rw-r--r--contrib/llvm/tools/opt/Makefile14
-rw-r--r--contrib/llvm/tools/opt/PrintSCC.cpp4
-rw-r--r--contrib/llvm/tools/opt/opt.cpp9
735 files changed, 115006 insertions, 44174 deletions
diff --git a/contrib/llvm/tools/bugpoint/BugDriver.cpp b/contrib/llvm/tools/bugpoint/BugDriver.cpp
index 677d178..6b219bf 100644
--- a/contrib/llvm/tools/bugpoint/BugDriver.cpp
+++ b/contrib/llvm/tools/bugpoint/BugDriver.cpp
@@ -87,7 +87,7 @@ Module *llvm::ParseInputFile(const std::string &Filename,
SMDiagnostic Err;
Module *Result = ParseIRFile(Filename, Err, Ctxt);
if (!Result)
- Err.Print("bugpoint", errs());
+ Err.print("bugpoint", errs());
// If we don't have an override triple, use the first one to configure
// bugpoint, or use the host triple if none provided.
@@ -96,7 +96,7 @@ Module *llvm::ParseInputFile(const std::string &Filename,
Triple TheTriple(Result->getTargetTriple());
if (TheTriple.getTriple().empty())
- TheTriple.setTriple(sys::getHostTriple());
+ TheTriple.setTriple(sys::getDefaultTargetTriple());
TargetTriple.setTriple(TheTriple.getTriple());
}
diff --git a/contrib/llvm/tools/bugpoint/CMakeLists.txt b/contrib/llvm/tools/bugpoint/CMakeLists.txt
deleted file mode 100644
index e06feb1..0000000
--- a/contrib/llvm/tools/bugpoint/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-set(LLVM_LINK_COMPONENTS asmparser instrumentation scalaropts ipo
- linker bitreader bitwriter)
-
-add_llvm_tool(bugpoint
- BugDriver.cpp
- CrashDebugger.cpp
- ExecutionDriver.cpp
- ExtractFunction.cpp
- FindBugs.cpp
- Miscompilation.cpp
- OptimizerDriver.cpp
- ToolRunner.cpp
- bugpoint.cpp
- )
diff --git a/contrib/llvm/tools/bugpoint/CrashDebugger.cpp b/contrib/llvm/tools/bugpoint/CrashDebugger.cpp
index f19ef62..aed16f4 100644
--- a/contrib/llvm/tools/bugpoint/CrashDebugger.cpp
+++ b/contrib/llvm/tools/bugpoint/CrashDebugger.cpp
@@ -169,7 +169,7 @@ ReduceCrashingGlobalVariables::TestGlobalVariables(
return false;
}
-namespace llvm {
+namespace {
/// ReduceCrashingFunctions reducer - This works by removing functions and
/// seeing if the program still crashes. If it does, then keep the newer,
/// smaller program.
@@ -401,7 +401,8 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*>
for (Function::iterator FI = MI->begin(), FE = MI->end(); FI != FE; ++FI)
for (BasicBlock::iterator I = FI->begin(), E = FI->end(); I != E;) {
Instruction *Inst = I++;
- if (!Instructions.count(Inst) && !isa<TerminatorInst>(Inst)) {
+ if (!Instructions.count(Inst) && !isa<TerminatorInst>(Inst) &&
+ !isa<LandingPadInst>(Inst)) {
if (!Inst->getType()->isVoidTy())
Inst->replaceAllUsesWith(UndefValue::get(Inst->getType()));
Inst->eraseFromParent();
@@ -568,12 +569,15 @@ static bool DebugACrash(BugDriver &BD,
for (Function::const_iterator BI = FI->begin(), E = FI->end(); BI != E;
++BI)
for (BasicBlock::const_iterator I = BI->begin(), E = --BI->end();
- I != E; ++I, ++CurInstructionNum)
+ I != E; ++I, ++CurInstructionNum) {
if (InstructionsToSkipBeforeDeleting) {
--InstructionsToSkipBeforeDeleting;
} else {
if (BugpointIsInterrupted) goto ExitLoops;
+ if (isa<LandingPadInst>(I))
+ continue;
+
outs() << "Checking instruction: " << *I;
Module *M = BD.deleteInstructionFromProgram(I, Simplification);
@@ -590,6 +594,7 @@ static bool DebugACrash(BugDriver &BD,
// one.
delete M;
}
+ }
if (InstructionsToSkipBeforeDeleting) {
InstructionsToSkipBeforeDeleting = 0;
diff --git a/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp b/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp
index 77c01ac..218a559 100644
--- a/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp
+++ b/contrib/llvm/tools/bugpoint/ExecutionDriver.cpp
@@ -28,8 +28,7 @@ namespace {
// for miscompilation.
//
enum OutputType {
- AutoPick, RunLLI, RunJIT, RunLLC, RunLLCIA, RunCBE, CBE_bug, LLC_Safe,
- CompileCustom, Custom
+ AutoPick, RunLLI, RunJIT, RunLLC, RunLLCIA, LLC_Safe, CompileCustom, Custom
};
cl::opt<double>
@@ -48,8 +47,6 @@ namespace {
clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
clEnumValN(RunLLCIA, "run-llc-ia",
"Compile with LLC with integrated assembler"),
- clEnumValN(RunCBE, "run-cbe", "Compile with CBE"),
- clEnumValN(CBE_bug,"cbe-bug", "Find CBE bugs"),
clEnumValN(LLC_Safe, "llc-safe", "Use LLC for all"),
clEnumValN(CompileCustom, "compile-custom",
"Use -compile-command to define a command to "
@@ -64,7 +61,6 @@ namespace {
SafeInterpreterSel(cl::desc("Specify \"safe\" i.e. known-good backend:"),
cl::values(clEnumValN(AutoPick, "safe-auto", "Use best guess"),
clEnumValN(RunLLC, "safe-run-llc", "Compile with LLC"),
- clEnumValN(RunCBE, "safe-run-cbe", "Compile with CBE"),
clEnumValN(Custom, "safe-run-custom",
"Use -exec-command to define a command to execute "
"the bitcode. Useful for cross-compilation."),
@@ -154,10 +150,6 @@ bool BugDriver::initializeExecutionEnvironment() {
switch (InterpreterSel) {
case AutoPick:
- InterpreterSel = RunCBE;
- Interpreter =
- AbstractInterpreter::createCBE(getToolName(), Message, GCCBinary,
- &ToolArgv, &GCCToolArgv);
if (!Interpreter) {
InterpreterSel = RunJIT;
Interpreter = AbstractInterpreter::createJIT(getToolName(), Message,
@@ -195,12 +187,6 @@ bool BugDriver::initializeExecutionEnvironment() {
Interpreter = AbstractInterpreter::createJIT(getToolName(), Message,
&ToolArgv);
break;
- case RunCBE:
- case CBE_bug:
- Interpreter = AbstractInterpreter::createCBE(getToolName(), Message,
- GCCBinary, &ToolArgv,
- &GCCToolArgv);
- break;
case CompileCustom:
Interpreter =
AbstractInterpreter::createCustomCompiler(Message, CustomCompileCommand);
@@ -209,9 +195,6 @@ bool BugDriver::initializeExecutionEnvironment() {
Interpreter =
AbstractInterpreter::createCustomExecutor(Message, CustomExecCommand);
break;
- default:
- Message = "Sorry, this back-end is not supported by bugpoint right now!\n";
- break;
}
if (!Interpreter)
errs() << Message;
@@ -224,17 +207,6 @@ bool BugDriver::initializeExecutionEnvironment() {
std::vector<std::string> SafeToolArgs = SafeToolArgv;
switch (SafeInterpreterSel) {
case AutoPick:
- // In "cbe-bug" mode, default to using LLC as the "safe" backend.
- if (!SafeInterpreter &&
- InterpreterSel == CBE_bug) {
- SafeInterpreterSel = RunLLC;
- SafeToolArgs.push_back("--relocation-model=pic");
- SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message,
- GCCBinary,
- &SafeToolArgs,
- &GCCToolArgv);
- }
-
// In "llc-safe" mode, default to using LLC as the "safe" backend.
if (!SafeInterpreter &&
InterpreterSel == LLC_Safe) {
@@ -246,17 +218,6 @@ bool BugDriver::initializeExecutionEnvironment() {
&GCCToolArgv);
}
- // Pick a backend that's different from the test backend. The JIT and
- // LLC backends share a lot of code, so prefer to use the CBE as the
- // safe back-end when testing them.
- if (!SafeInterpreter &&
- InterpreterSel != RunCBE) {
- SafeInterpreterSel = RunCBE;
- SafeInterpreter = AbstractInterpreter::createCBE(Path.c_str(), Message,
- GCCBinary,
- &SafeToolArgs,
- &GCCToolArgv);
- }
if (!SafeInterpreter &&
InterpreterSel != RunLLC &&
InterpreterSel != RunJIT) {
@@ -280,11 +241,6 @@ bool BugDriver::initializeExecutionEnvironment() {
&GCCToolArgv,
SafeInterpreterSel == RunLLCIA);
break;
- case RunCBE:
- SafeInterpreter = AbstractInterpreter::createCBE(Path.c_str(), Message,
- GCCBinary, &SafeToolArgs,
- &GCCToolArgv);
- break;
case Custom:
SafeInterpreter =
AbstractInterpreter::createCustomExecutor(Message, CustomExecCommand);
@@ -462,8 +418,8 @@ bool BugDriver::createReferenceFile(Module *M, const std::string &Filename) {
errs() << Error;
if (Interpreter != SafeInterpreter) {
errs() << "*** There is a bug running the \"safe\" backend. Either"
- << " debug it (for example with the -run-cbe bugpoint option,"
- << " if CBE is being used as the \"safe\" backend), or fix the"
+ << " debug it (for example with the -run-jit bugpoint option,"
+ << " if JIT is being used as the \"safe\" backend), or fix the"
<< " error some other way.\n";
}
return false;
diff --git a/contrib/llvm/tools/bugpoint/ExtractFunction.cpp b/contrib/llvm/tools/bugpoint/ExtractFunction.cpp
index 73b65ca..ac8e159 100644
--- a/contrib/llvm/tools/bugpoint/ExtractFunction.cpp
+++ b/contrib/llvm/tools/bugpoint/ExtractFunction.cpp
@@ -47,7 +47,39 @@ namespace {
cl::opt<bool, true>
NoSCFG("disable-simplifycfg", cl::location(DisableSimplifyCFG),
cl::desc("Do not use the -simplifycfg pass to reduce testcases"));
-}
+
+ Function* globalInitUsesExternalBA(GlobalVariable* GV) {
+ if (!GV->hasInitializer())
+ return 0;
+
+ Constant *I = GV->getInitializer();
+
+ // walk the values used by the initializer
+ // (and recurse into things like ConstantExpr)
+ std::vector<Constant*> Todo;
+ std::set<Constant*> Done;
+ Todo.push_back(I);
+
+ while (!Todo.empty()) {
+ Constant* V = Todo.back();
+ Todo.pop_back();
+ Done.insert(V);
+
+ if (BlockAddress *BA = dyn_cast<BlockAddress>(V)) {
+ Function *F = BA->getFunction();
+ if (F->isDeclaration())
+ return F;
+ }
+
+ for (User::op_iterator i = V->op_begin(), e = V->op_end(); i != e; ++i) {
+ Constant *C = dyn_cast<Constant>(*i);
+ if (C && !isa<GlobalValue>(C) && !Done.count(C))
+ Todo.push_back(C);
+ }
+ }
+ return 0;
+ }
+} // end anonymous namespace
/// deleteInstructionFromProgram - This method clones the current Program and
/// deletes the specified instruction from the cloned module. It then runs a
@@ -272,11 +304,6 @@ llvm::SplitFunctionsOutOfModule(Module *M,
ValueToValueMapTy NewVMap;
Module *New = CloneModule(M, NewVMap);
- // Make sure global initializers exist only in the safe module (CBE->.so)
- for (Module::global_iterator I = New->global_begin(), E = New->global_end();
- I != E; ++I)
- I->setInitializer(0); // Delete the initializer to make it external
-
// Remove the Test functions from the Safe module
std::set<Function *> TestFunctions;
for (unsigned i = 0, e = F.size(); i != e; ++i) {
@@ -295,6 +322,27 @@ llvm::SplitFunctionsOutOfModule(Module *M,
DeleteFunctionBody(I);
+ // Try to split the global initializers evenly
+ for (Module::global_iterator I = M->global_begin(), E = M->global_end();
+ I != E; ++I) {
+ GlobalVariable *GV = cast<GlobalVariable>(NewVMap[I]);
+ if (Function *TestFn = globalInitUsesExternalBA(I)) {
+ if (Function *SafeFn = globalInitUsesExternalBA(GV)) {
+ errs() << "*** Error: when reducing functions, encountered "
+ "the global '";
+ WriteAsOperand(errs(), GV, false);
+ errs() << "' with an initializer that references blockaddresses "
+ "from safe function '" << SafeFn->getName()
+ << "' and from test function '" << TestFn->getName() << "'.\n";
+ exit(1);
+ }
+ I->setInitializer(0); // Delete the initializer to make it external
+ } else {
+ // If we keep it in the safe module, then delete it in the test module
+ GV->setInitializer(0);
+ }
+ }
+
// Make sure that there is a global ctor/dtor array in both halves of the
// module if they both have static ctor/dtor functions.
SplitStaticCtorDtor("llvm.global_ctors", M, New, NewVMap);
@@ -340,7 +388,7 @@ Module *BugDriver::ExtractMappedBlocksFromModule(const
// If the BB doesn't have a name, give it one so we have something to key
// off of.
if (!BB->hasName()) BB->setName("tmpbb");
- BlocksToNotExtractFile.os() << BB->getParent()->getNameStr() << " "
+ BlocksToNotExtractFile.os() << BB->getParent()->getName() << " "
<< BB->getName() << "\n";
}
BlocksToNotExtractFile.os().close();
diff --git a/contrib/llvm/tools/bugpoint/Makefile b/contrib/llvm/tools/bugpoint/Makefile
deleted file mode 100644
index 5d287ef..0000000
--- a/contrib/llvm/tools/bugpoint/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-##===- tools/bugpoint/Makefile -----------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-LEVEL = ../..
-
-TOOLNAME = bugpoint
-
-LINK_COMPONENTS := asmparser instrumentation scalaropts ipo \
- linker bitreader bitwriter
-
-include $(LEVEL)/Makefile.common
diff --git a/contrib/llvm/tools/bugpoint/Miscompilation.cpp b/contrib/llvm/tools/bugpoint/Miscompilation.cpp
index 7ff16db..82a3a86 100644
--- a/contrib/llvm/tools/bugpoint/Miscompilation.cpp
+++ b/contrib/llvm/tools/bugpoint/Miscompilation.cpp
@@ -820,7 +820,8 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test,
// Don't forward functions which are external in the test module too.
if (TestFn && !TestFn->isDeclaration()) {
// 1. Add a string constant with its name to the global file
- Constant *InitArray = ConstantArray::get(F->getContext(), F->getName());
+ Constant *InitArray =
+ ConstantDataArray::getString(F->getContext(), F->getName());
GlobalVariable *funcName =
new GlobalVariable(*Safe, InitArray->getType(), true /*isConstant*/,
GlobalValue::InternalLinkage, InitArray,
diff --git a/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp b/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp
index 336c83d..fb090ee 100644
--- a/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp
+++ b/contrib/llvm/tools/bugpoint/OptimizerDriver.cpp
@@ -85,8 +85,11 @@ void BugDriver::EmitProgressBitcode(const Module *M,
if (NoFlyer || PassesToRun.empty()) return;
outs() << "\n*** You can reproduce the problem with: ";
if (UseValgrind) outs() << "valgrind ";
- outs() << "opt " << Filename << " ";
- outs() << getPassesString(PassesToRun) << "\n";
+ outs() << "opt " << Filename;
+ for (unsigned i = 0, e = PluginLoader::getNumPlugins(); i != e; ++i) {
+ outs() << " -load " << PluginLoader::getPlugin(i);
+ }
+ outs() << " " << getPassesString(PassesToRun) << "\n";
}
cl::opt<bool> SilencePasses("silence-passes",
@@ -145,10 +148,9 @@ bool BugDriver::runPasses(Module *Program,
return 1;
}
- sys::Path tool = PrependMainExecutablePath("opt", getToolName(),
- (void*)"opt");
+ sys::Path tool = sys::Program::FindProgramByName("opt");
if (tool.empty()) {
- errs() << "Cannot find `opt' in executable directory!\n";
+ errs() << "Cannot find `opt' in PATH!\n";
return 1;
}
diff --git a/contrib/llvm/tools/bugpoint/ToolRunner.cpp b/contrib/llvm/tools/bugpoint/ToolRunner.cpp
index 0d98262..25a2bae 100644
--- a/contrib/llvm/tools/bugpoint/ToolRunner.cpp
+++ b/contrib/llvm/tools/bugpoint/ToolRunner.cpp
@@ -234,6 +234,8 @@ int LLI::ExecuteProgram(const std::string &Bitcode,
Timeout, MemoryLimit, Error);
}
+void AbstractInterpreter::anchor() { }
+
// LLI create method - Try to find the LLI executable
AbstractInterpreter *AbstractInterpreter::createLLI(const char *Argv0,
std::string &Message,
@@ -621,94 +623,6 @@ AbstractInterpreter *AbstractInterpreter::createJIT(const char *Argv0,
return 0;
}
-GCC::FileType CBE::OutputCode(const std::string &Bitcode,
- sys::Path &OutputCFile, std::string &Error,
- unsigned Timeout, unsigned MemoryLimit) {
- sys::Path uniqueFile(Bitcode+".cbe.c");
- std::string ErrMsg;
- if (uniqueFile.makeUnique(true, &ErrMsg)) {
- errs() << "Error making unique filename: " << ErrMsg << "\n";
- exit(1);
- }
- OutputCFile = uniqueFile;
- std::vector<const char *> LLCArgs;
- LLCArgs.push_back(LLCPath.c_str());
-
- // Add any extra LLC args.
- for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
- LLCArgs.push_back(ToolArgs[i].c_str());
-
- LLCArgs.push_back("-o");
- LLCArgs.push_back(OutputCFile.c_str()); // Output to the C file
- LLCArgs.push_back("-march=c"); // Output C language
- LLCArgs.push_back(Bitcode.c_str()); // This is the input bitcode
- LLCArgs.push_back(0);
-
- outs() << "<cbe>"; outs().flush();
- DEBUG(errs() << "\nAbout to run:\t";
- for (unsigned i = 0, e = LLCArgs.size()-1; i != e; ++i)
- errs() << " " << LLCArgs[i];
- errs() << "\n";
- );
- if (RunProgramWithTimeout(LLCPath, &LLCArgs[0], sys::Path(), sys::Path(),
- sys::Path(), Timeout, MemoryLimit))
- Error = ProcessFailure(LLCPath, &LLCArgs[0], Timeout, MemoryLimit);
- return GCC::CFile;
-}
-
-void CBE::compileProgram(const std::string &Bitcode, std::string *Error,
- unsigned Timeout, unsigned MemoryLimit) {
- sys::Path OutputCFile;
- OutputCode(Bitcode, OutputCFile, *Error, Timeout, MemoryLimit);
- OutputCFile.eraseFromDisk();
-}
-
-int CBE::ExecuteProgram(const std::string &Bitcode,
- const std::vector<std::string> &Args,
- const std::string &InputFile,
- const std::string &OutputFile,
- std::string *Error,
- const std::vector<std::string> &ArgsForGCC,
- const std::vector<std::string> &SharedLibs,
- unsigned Timeout,
- unsigned MemoryLimit) {
- sys::Path OutputCFile;
- OutputCode(Bitcode, OutputCFile, *Error, Timeout, MemoryLimit);
-
- FileRemover CFileRemove(OutputCFile.str(), !SaveTemps);
-
- std::vector<std::string> GCCArgs(ArgsForGCC);
- GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end());
-
- return gcc->ExecuteProgram(OutputCFile.str(), Args, GCC::CFile,
- InputFile, OutputFile, Error, GCCArgs,
- Timeout, MemoryLimit);
-}
-
-/// createCBE - Try to find the 'llc' executable
-///
-CBE *AbstractInterpreter::createCBE(const char *Argv0,
- std::string &Message,
- const std::string &GCCBinary,
- const std::vector<std::string> *Args,
- const std::vector<std::string> *GCCArgs) {
- sys::Path LLCPath =
- PrependMainExecutablePath("llc", Argv0, (void *)(intptr_t)&createCBE);
- if (LLCPath.isEmpty()) {
- Message =
- "Cannot find `llc' in executable directory!\n";
- return 0;
- }
-
- Message = "Found llc: " + LLCPath.str() + "\n";
- GCC *gcc = GCC::create(Message, GCCBinary, GCCArgs);
- if (!gcc) {
- errs() << Message << "\n";
- exit(1);
- }
- return new CBE(LLCPath, gcc, Args);
-}
-
//===---------------------------------------------------------------------===//
// GCC abstraction
//
@@ -920,8 +834,7 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType,
} else
GCCArgs.push_back("-shared"); // `-shared' for Linux/X86, maybe others
- if ((TargetTriple.getArch() == Triple::alpha) ||
- (TargetTriple.getArch() == Triple::x86_64))
+ if (TargetTriple.getArch() == Triple::x86_64)
GCCArgs.push_back("-fPIC"); // Requires shared objs to contain PIC
if (TargetTriple.getArch() == Triple::sparc)
diff --git a/contrib/llvm/tools/bugpoint/ToolRunner.h b/contrib/llvm/tools/bugpoint/ToolRunner.h
index cfa8acf..7b93394 100644
--- a/contrib/llvm/tools/bugpoint/ToolRunner.h
+++ b/contrib/llvm/tools/bugpoint/ToolRunner.h
@@ -86,6 +86,7 @@ public:
/// complexity behind a simple interface.
///
class AbstractInterpreter {
+ virtual void anchor();
public:
static CBE *createCBE(const char *Argv0, std::string &Message,
const std::string &GCCBinary,
diff --git a/contrib/llvm/tools/bugpoint/bugpoint.cpp b/contrib/llvm/tools/bugpoint/bugpoint.cpp
index 6a87521..8f15b02 100644
--- a/contrib/llvm/tools/bugpoint/bugpoint.cpp
+++ b/contrib/llvm/tools/bugpoint/bugpoint.cpp
@@ -120,6 +120,7 @@ int main(int argc, char **argv) {
PassRegistry &Registry = *PassRegistry::getPassRegistry();
initializeCore(Registry);
initializeScalarOpts(Registry);
+ initializeVectorization(Registry);
initializeIPO(Registry);
initializeAnalysis(Registry);
initializeIPA(Registry);
diff --git a/contrib/llvm/tools/clang/LICENSE.TXT b/contrib/llvm/tools/clang/LICENSE.TXT
index 91895eb..6c224f8 100644
--- a/contrib/llvm/tools/clang/LICENSE.TXT
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang-c/Index.h b/contrib/llvm/tools/clang/include/clang-c/Index.h
index 1320145..13ba6ba 100644
--- a/contrib/llvm/tools/clang/include/clang-c/Index.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/ARCMigrate/ARCMT.h b/contrib/llvm/tools/clang/include/clang/ARCMigrate/ARCMT.h
index d8dea0b..86a6cbb 100644
--- a/contrib/llvm/tools/clang/include/clang/ARCMigrate/ARCMT.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/ARCMigrate/ARCMTActions.h b/contrib/llvm/tools/clang/include/clang/ARCMigrate/ARCMTActions.h
index 4eac4fa..e075252 100644
--- a/contrib/llvm/tools/clang/include/clang/ARCMigrate/ARCMTActions.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/ARCMigrate/FileRemapper.h b/contrib/llvm/tools/clang/include/clang/ARCMigrate/FileRemapper.h
index 9a0b690..fe7cfad 100644
--- a/contrib/llvm/tools/clang/include/clang/ARCMigrate/FileRemapper.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/APValue.h b/contrib/llvm/tools/clang/include/clang/AST/APValue.h
index 375af28..1b6e90c 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/APValue.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/ASTConsumer.h b/contrib/llvm/tools/clang/include/clang/AST/ASTConsumer.h
index fcc9176..69a3866 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/ASTConsumer.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/ASTContext.h b/contrib/llvm/tools/clang/include/clang/AST/ASTContext.h
index 48d7e94..96e41c5 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/ASTContext.h
+++ b/contrib/llvm/tools/clang/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;
@@ -318,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.
@@ -346,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.
@@ -355,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;
@@ -364,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; }
@@ -394,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;
@@ -468,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;
@@ -482,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; }
@@ -500,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'.
@@ -519,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.
@@ -800,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,
@@ -815,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,
@@ -838,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.
@@ -851,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;
@@ -874,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 {
@@ -972,7 +1058,7 @@ public:
/// \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
@@ -999,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
@@ -1041,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;
@@ -1055,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; }
@@ -1064,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())
@@ -1127,6 +1225,7 @@ public:
private:
CanQualType getFromTargetType(unsigned Type) const;
+ std::pair<uint64_t, unsigned> getTypeInfoImpl(const Type *T) const;
//===--------------------------------------------------------------------===//
// Type Predicates.
@@ -1230,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
@@ -1246,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();
@@ -1282,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);
}
@@ -1302,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();
}
@@ -1590,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.
@@ -1622,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);
@@ -1671,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.
@@ -1751,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;
@@ -1795,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)
@@ -1819,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.
@@ -1828,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)
@@ -1853,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);
}
@@ -1863,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/contrib/llvm/tools/clang/include/clang/AST/ASTDiagnostic.h b/contrib/llvm/tools/clang/include/clang/AST/ASTDiagnostic.h
index b005711..64e955e 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/ASTDiagnostic.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/ASTImporter.h b/contrib/llvm/tools/clang/include/clang/AST/ASTImporter.h
index b583fbf..7157efe 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/ASTImporter.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/ASTMutationListener.h b/contrib/llvm/tools/clang/include/clang/AST/ASTMutationListener.h
index 793d3ee..cb038a0 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/ASTMutationListener.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/Attr.h b/contrib/llvm/tools/clang/include/clang/AST/Attr.h
index cf2e3c5..ef1aa25 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/Attr.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/BuiltinTypes.def b/contrib/llvm/tools/clang/include/clang/AST/BuiltinTypes.def
new file mode 100644
index 0000000..34e6fc5
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/CanonicalType.h b/contrib/llvm/tools/clang/include/clang/AST/CanonicalType.h
index 38e6b41..6cce888 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/CanonicalType.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/Decl.h b/contrib/llvm/tools/clang/include/clang/AST/Decl.h
index a02a2ce..11696db 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/Decl.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h b/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h
index 9f29411..4c675aed 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h b/contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h
index 7e60773..7f3ec4c 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/DeclCXX.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/DeclFriend.h b/contrib/llvm/tools/clang/include/clang/AST/DeclFriend.h
index b84e5bb..ba1eb8d 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/DeclFriend.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/DeclLookups.h b/contrib/llvm/tools/clang/include/clang/AST/DeclLookups.h
new file mode 100644
index 0000000..66d190f
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h b/contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h
index 425c89d..4ae073e 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/DeclObjC.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h b/contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h
index 138e47d..36549ea 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/DeclTemplate.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/DeclVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/DeclVisitor.h
index b5b6bd4..62654b8 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/DeclVisitor.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h b/contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h
index 2170f2b..6349d9c 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/DeclarationName.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/DependentDiagnostic.h b/contrib/llvm/tools/clang/include/clang/AST/DependentDiagnostic.h
index 2bbe502..948dcb4 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/DependentDiagnostic.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/Expr.h b/contrib/llvm/tools/clang/include/clang/AST/Expr.h
index 1242f4e..558bd00 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/Expr.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h b/contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h
index 3cc09cd..b69693d 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/ExprCXX.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/ExprObjC.h b/contrib/llvm/tools/clang/include/clang/AST/ExprObjC.h
index 55726eb..4bfd12c 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/ExprObjC.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h b/contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h
index 96d14b2..18a1432 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/ExternalASTSource.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/LambdaMangleContext.h b/contrib/llvm/tools/clang/include/clang/AST/LambdaMangleContext.h
new file mode 100644
index 0000000..3e2fbad
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/Mangle.h b/contrib/llvm/tools/clang/include/clang/AST/Mangle.h
index f58a83b..ca22ed6 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/Mangle.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/NSAPI.h b/contrib/llvm/tools/clang/include/clang/AST/NSAPI.h
new file mode 100644
index 0000000..40e9759
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/NestedNameSpecifier.h b/contrib/llvm/tools/clang/include/clang/AST/NestedNameSpecifier.h
index c81c06e..b5bd824 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/NestedNameSpecifier.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/OperationKinds.h b/contrib/llvm/tools/clang/include/clang/AST/OperationKinds.h
index 469da99..258637d 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/OperationKinds.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/PrettyPrinter.h b/contrib/llvm/tools/clang/include/clang/AST/PrettyPrinter.h
index 2bdd8d3..2e34dc8 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/PrettyPrinter.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/RecordLayout.h b/contrib/llvm/tools/clang/include/clang/AST/RecordLayout.h
index b0186ce..ec07267 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/RecordLayout.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h
index 0ec09c9..a4ad525 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h b/contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h
index e87ca78..88abadb 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/Redeclarable.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/Stmt.h b/contrib/llvm/tools/clang/include/clang/AST/Stmt.h
index 2a6fd6b..84bdfb8 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/Stmt.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/StmtCXX.h b/contrib/llvm/tools/clang/include/clang/AST/StmtCXX.h
index 42dcf2b..a948722 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/StmtCXX.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h b/contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h
index 05b50db..b933ed0 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/StmtIterator.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/StmtObjC.h b/contrib/llvm/tools/clang/include/clang/AST/StmtObjC.h
index d996fc5..a321041 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/StmtObjC.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/StmtVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/StmtVisitor.h
index 48a0123..38c4c02 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/StmtVisitor.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h b/contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h
index 371c27a..65f5460 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/TemplateBase.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/Type.h b/contrib/llvm/tools/clang/include/clang/AST/Type.h
index dd9aa56..7bd367c 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/Type.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h b/contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h
index 20acada..aab87be 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/TypeLoc.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/TypeVisitor.h b/contrib/llvm/tools/clang/include/clang/AST/TypeVisitor.h
index 9eebc4b..242aa58 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/TypeVisitor.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/UsuallyTinyPtrVector.h b/contrib/llvm/tools/clang/include/clang/AST/UsuallyTinyPtrVector.h
deleted file mode 100644
index 534d4d4..0000000
--- a/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/AST/VTableBuilder.h b/contrib/llvm/tools/clang/include/clang/AST/VTableBuilder.h
index 59bab03..2aa9a3d 100644
--- a/contrib/llvm/tools/clang/include/clang/AST/VTableBuilder.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Dominators.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/Dominators.h
new file mode 100644
index 0000000..e9a431a
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/FormatString.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/FormatString.h
index a3f9c53..d4d8dc0 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/FormatString.h
+++ b/contrib/llvm/tools/clang/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,49 +133,49 @@ public:
aArg,
AArg,
DoubleArgBeg = fArg, DoubleArgEnd = AArg,
-
+
sArg,
pArg,
nArg,
PercentArg,
CArg,
SArg,
-
+
// ** Printf-specific **
-
+
// Objective-C specific specifiers.
ObjCObjArg, // '@'
ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg,
-
+
// FreeBSD specific specifiers
bArg,
DArg,
rArg,
-
+
// 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:
@@ -183,15 +186,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:
@@ -204,15 +208,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); }
@@ -227,6 +234,8 @@ public:
bool matchesAnyObjCObjectRef() const { return K == ObjCPointerTy; }
QualType getRepresentativeType(ASTContext &C) const;
+
+ std::string getRepresentativeTypeName(ASTContext &C) const;
};
class OptionalAmount {
@@ -302,9 +311,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:
@@ -342,8 +351,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
@@ -353,7 +368,7 @@ public:
namespace analyze_printf {
-class PrintfConversionSpecifier :
+class PrintfConversionSpecifier :
public analyze_format_string::ConversionSpecifier {
public:
PrintfConversionSpecifier()
@@ -364,9 +379,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.
@@ -443,7 +457,7 @@ public:
const OptionalAmount &getPrecision() const {
return Precision;
}
-
+
bool consumesDataArgument() const {
return getConversionSpecifier().consumesDataArgument();
}
@@ -453,9 +467,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; }
@@ -465,14 +479,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;
@@ -500,16 +515,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:
@@ -533,11 +573,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);
};
@@ -557,6 +603,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) {}
@@ -599,11 +647,10 @@ public:
};
bool ParsePrintfString(FormatStringHandler &H,
- const char *beg, const char *end,
- bool FormatExtensions);
+ 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/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/LiveVariables.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/LiveVariables.h
index 302ae1c..c9f39b4 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/LiveVariables.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/PostOrderCFGView.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/PostOrderCFGView.h
new file mode 100644
index 0000000..4e3244e
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ReachableCode.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ReachableCode.h
index 6cf7fa4..30c5b2d 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ReachableCode.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafety.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafety.h
index a325056..26e258d 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/ThreadSafety.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/UninitializedValues.h b/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/UninitializedValues.h
index e2e4f35..4ee6698 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/Analyses/UninitializedValues.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h b/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h
index 3d0e88a..6b6f8ef 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisDiagnostic.h
index 16d31b4..d4e1f5f 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/AnalysisDiagnostic.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Analysis/CFG.h b/contrib/llvm/tools/clang/include/clang/Analysis/CFG.h
index f191c80..27b22b8 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/CFG.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Analysis/CallGraph.h b/contrib/llvm/tools/clang/include/clang/Analysis/CallGraph.h
new file mode 100644
index 0000000..9b68073
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Analysis/DomainSpecific/CocoaConventions.h b/contrib/llvm/tools/clang/include/clang/Analysis/DomainSpecific/CocoaConventions.h
index fa8afcc..e6a2f13 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/DomainSpecific/CocoaConventions.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Analysis/ProgramPoint.h b/contrib/llvm/tools/clang/include/clang/Analysis/ProgramPoint.h
index 7ec4ecd..b2200c6 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/ProgramPoint.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Analysis/Support/SaveAndRestore.h b/contrib/llvm/tools/clang/include/clang/Analysis/Support/SaveAndRestore.h
deleted file mode 100644
index f720639..0000000
--- a/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/contrib/llvm/tools/clang/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
index 5c5ec2d..97eb287 100644
--- a/contrib/llvm/tools/clang/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/AllDiagnostics.h b/contrib/llvm/tools/clang/include/clang/Basic/AllDiagnostics.h
new file mode 100644
index 0000000..7e77435
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/Attr.td b/contrib/llvm/tools/clang/include/clang/Basic/Attr.td
index 2a4ba5c..e8e0f35 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Attr.td
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def b/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def
index da5aadf..d1af218 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def
+++ b/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def
@@ -108,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")
@@ -363,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")
@@ -448,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")
@@ -587,18 +594,57 @@ BUILTIN(__sync_swap_4, "iiD*i.", "tn")
BUILTIN(__sync_swap_8, "LLiLLiD*LLi.", "tn")
BUILTIN(__sync_swap_16, "LLLiLLLiD*LLLi.", "tn")
-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")
+// 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")
@@ -629,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)
@@ -655,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)
@@ -671,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)
@@ -698,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, ...)
@@ -712,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/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsHexagon.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsHexagon.def
new file mode 100644
index 0000000..334224f
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def
index 6bd9014..f44aed6 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/ConvertUTF.h b/contrib/llvm/tools/clang/include/clang/Basic/ConvertUTF.h
index d928f9d..ec6b973 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/ConvertUTF.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td b/contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td
index a37dc10..6f2bb35 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DeclNodes.td
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h
index fefc44c..e157178 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td b/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td
index 8ae69fe..109cd08 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Diagnostic.td
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td
index 705c95b..9cfe5ef 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticAnalysisKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticAnalysisKinds.td
index 46dc0e6..5461212 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticAnalysisKinds.td
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td
index f9a910a..103fc00 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 3c0e4f5..b443159 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index fffa42f..5d6b887 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td
index 00a6663..c839853 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td
@@ -25,7 +25,14 @@ 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">;
@@ -55,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">;
@@ -95,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">;
@@ -133,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">;
@@ -155,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">;
@@ -205,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]>;
@@ -226,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:
@@ -234,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",
@@ -253,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,
@@ -284,8 +342,8 @@ def Most : DiagGroup<"most", [
Reorder,
ReturnType,
SelfAssignment,
- Switch,
SizeofArrayArgument,
+ StringPlusInt,
Trigraphs,
Uninitialized,
UnknownPragmas,
@@ -298,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.
@@ -318,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">;
@@ -330,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/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h
index 16d9b39..a6c22db 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticIDs.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td
index 9b3a178..670283e 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td
index 73437b2..c183da7 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d60e69b..e553740 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/contrib/llvm/tools/clang/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,7 +289,7 @@ 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'">;
@@ -269,7 +311,8 @@ def warn_redecl_library_builtin : Warning<
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 "
@@ -292,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++.
@@ -299,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">,
@@ -339,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<
@@ -370,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">;
@@ -479,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<
@@ -495,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<
@@ -505,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">;
@@ -531,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 "
@@ -571,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"
@@ -608,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">;
@@ -625,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<
@@ -681,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'">;
@@ -720,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">,
@@ -744,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;
@@ -769,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<
@@ -821,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<
@@ -885,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<
@@ -895,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<
@@ -983,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">;
@@ -1015,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<
@@ -1055,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">;
@@ -1063,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<
@@ -1104,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<
@@ -1116,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<
@@ -1132,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<
@@ -1154,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<
@@ -1171,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<
@@ -1197,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">;
@@ -1207,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<
@@ -1247,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<
@@ -1269,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<
@@ -1293,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<
@@ -1347,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<
@@ -1367,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<
@@ -1386,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<
@@ -1395,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<
@@ -1414,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<
@@ -1455,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">;
@@ -1479,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;
@@ -1495,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;
@@ -1530,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;
@@ -1548,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;
@@ -1560,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">,
@@ -1605,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<
@@ -1617,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<
@@ -1650,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<
@@ -1713,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">;
@@ -1733,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.
@@ -1766,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<
@@ -1811,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
@@ -1979,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<
@@ -1986,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 :
@@ -2017,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">;
@@ -2063,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">;
@@ -2103,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<
@@ -2121,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)">;
@@ -2156,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<
@@ -2181,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">;
@@ -2193,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">;
@@ -2303,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">;
@@ -2315,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"
@@ -2334,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">;
@@ -2376,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<
@@ -2392,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">;
@@ -2420,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">;
@@ -2454,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">;
@@ -2462,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<
@@ -2472,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'">;
@@ -2480,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<
@@ -2503,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<
@@ -2576,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>;
@@ -2599,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<
@@ -2606,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">;
@@ -2632,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<
@@ -2692,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<
@@ -2707,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<
@@ -2719,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">;
@@ -2731,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<
@@ -2756,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">,
@@ -2789,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 "
@@ -2801,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">;
@@ -2810,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<
@@ -2896,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<
@@ -2913,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<
@@ -2935,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">;
@@ -2944,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{"
@@ -2956,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">;
@@ -2988,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<
@@ -3011,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">;
@@ -3029,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">;
@@ -3038,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">;
@@ -3050,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
@@ -3086,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<
@@ -3105,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>;
@@ -3124,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">;
@@ -3185,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>;
@@ -3232,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;
@@ -3244,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<
@@ -3252,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<
@@ -3313,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">;
@@ -3355,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<
@@ -3383,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">;
@@ -3414,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 "
@@ -3441,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<
@@ -3470,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<
@@ -3486,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<
@@ -3553,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>;
@@ -3566,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<
@@ -3604,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<
@@ -3625,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<
@@ -3675,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<
@@ -3689,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<
@@ -3703,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<
@@ -3717,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<
@@ -3728,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">;
@@ -3757,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 "
@@ -3775,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">;
@@ -3791,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">;
@@ -3809,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<
@@ -3824,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">,
@@ -3848,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
@@ -3863,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 "
@@ -3880,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 "
@@ -3914,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"
@@ -3939,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"
@@ -3970,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)">;
@@ -3990,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<
@@ -4018,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<
@@ -4031,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">;
@@ -4061,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)">;
@@ -4101,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<
@@ -4112,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>;
@@ -4126,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 '('">;
@@ -4171,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<
@@ -4183,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">;
@@ -4219,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<
@@ -4259,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<
@@ -4283,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">;
@@ -4353,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">;
@@ -4391,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<
@@ -4454,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 "
@@ -4467,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">;
@@ -4492,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)">,
@@ -4506,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<
@@ -4529,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">,
@@ -4603,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">;
@@ -4639,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<
@@ -4668,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">;
@@ -4702,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">>;
@@ -4775,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<
@@ -4809,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;
@@ -4916,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__">;
@@ -4927,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/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td
new file mode 100644
index 0000000..7f9fe26
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/ExpressionTraits.h b/contrib/llvm/tools/clang/include/clang/Basic/ExpressionTraits.h
index 403a59a..c4e6a1c 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/ExpressionTraits.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/FileManager.h b/contrib/llvm/tools/clang/include/clang/Basic/FileManager.h
index ea8ed9f..5c7d9eb 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/FileManager.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/FileSystemStatCache.h b/contrib/llvm/tools/clang/include/clang/Basic/FileSystemStatCache.h
index 77828b3..96a2f90 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/FileSystemStatCache.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h b/contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h
index 5e48a86..cc0080b 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/IdentifierTable.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/LLVM.h b/contrib/llvm/tools/clang/include/clang/Basic/LLVM.h
index 27c459d..813b49e 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/LLVM.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/Lambda.h b/contrib/llvm/tools/clang/include/clang/Basic/Lambda.h
new file mode 100644
index 0000000..df50d94
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def
index c8389ab..786ae12 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.def
+++ b/contrib/llvm/tools/clang/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")
@@ -91,16 +91,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")
@@ -117,17 +119,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")
@@ -146,11 +154,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/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h b/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h
index 688047f..ce4ff06 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/LangOptions.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/Linkage.h b/contrib/llvm/tools/clang/include/clang/Basic/Linkage.h
index 01b6c79..09a5a0b 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Linkage.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/Module.h b/contrib/llvm/tools/clang/include/clang/Basic/Module.h
new file mode 100644
index 0000000..82dbd5b
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/OnDiskHashTable.h b/contrib/llvm/tools/clang/include/clang/Basic/OnDiskHashTable.h
index 7328b1a..8028a73 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/OnDiskHashTable.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/PartialDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Basic/PartialDiagnostic.h
index c6ca989..007e6a4 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/PartialDiagnostic.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h b/contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h
index 154148c..d5fa7e7 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/SourceLocation.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h b/contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h
index 985ddd6..bcb2d56 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/SourceManager.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h b/contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h
index 2a95d61..9e71827 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Specifiers.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/StmtNodes.td b/contrib/llvm/tools/clang/include/clang/Basic/StmtNodes.td
index 7b3d776..67d71e4 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/StmtNodes.td
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h b/contrib/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h
index 8bc60ff..7c04bf7 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h b/contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h
index a87af2f..bbd376a 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/TargetInfo.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def b/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def
index 35a881c..2e4d34d 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/TokenKinds.def
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h b/contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h
index a7a45bd..721f44f 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/TypeTraits.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Basic/Version.h b/contrib/llvm/tools/clang/include/clang/Basic/Version.h
index 15cdf1f..f3f5b5a 100644
--- a/contrib/llvm/tools/clang/include/clang/Basic/Version.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenAction.h b/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenAction.h
index f1a2f6e..7fa589f 100644
--- a/contrib/llvm/tools/clang/include/clang/CodeGen/CodeGenAction.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h b/contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h
index 38aba89..ba9d1f9 100644
--- a/contrib/llvm/tools/clang/include/clang/CodeGen/ModuleBuilder.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Driver/Action.h b/contrib/llvm/tools/clang/include/clang/Driver/Action.h
index a33c33b..6e317a0 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/Action.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Driver/ArgList.h b/contrib/llvm/tools/clang/include/clang/Driver/ArgList.h
index 04faf64..3affb00 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/ArgList.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Driver/CC1AsOptions.td b/contrib/llvm/tools/clang/include/clang/Driver/CC1AsOptions.td
index b1067b7..37ba602 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/CC1AsOptions.td
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td b/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td
index 1a12e98..88009ed 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td
+++ b/contrib/llvm/tools/clang/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 fformat_extensions : Flag<"-fformat-extensions">,
@@ -541,6 +634,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">,
@@ -555,6 +650,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">,
@@ -569,6 +666,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">;
@@ -595,10 +694,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
@@ -613,11 +718,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">;
@@ -639,6 +746,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>">,
@@ -693,6 +802,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/contrib/llvm/tools/clang/include/clang/Driver/Compilation.h b/contrib/llvm/tools/clang/include/clang/Driver/Compilation.h
index 8c99909..fd88c3a 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/Compilation.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Driver/Driver.h b/contrib/llvm/tools/clang/include/clang/Driver/Driver.h
index 6fdf6fc..0538334 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/Driver.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Driver/DriverDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Driver/DriverDiagnostic.h
index 844f918..ea7b52f 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/DriverDiagnostic.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Driver/HostInfo.h b/contrib/llvm/tools/clang/include/clang/Driver/HostInfo.h
deleted file mode 100644
index 7285a48..0000000
--- a/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Driver/Job.h b/contrib/llvm/tools/clang/include/clang/Driver/Job.h
index 367955f..c94886d 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/Job.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Driver/ObjCRuntime.h b/contrib/llvm/tools/clang/include/clang/Driver/ObjCRuntime.h
index 5516460..094873a 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/ObjCRuntime.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Driver/OptTable.h b/contrib/llvm/tools/clang/include/clang/Driver/OptTable.h
index abd224d..3af6f8f 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/OptTable.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Driver/Options.td b/contrib/llvm/tools/clang/include/clang/Driver/Options.td
index 5b91c19..0a29bb9 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/Options.td
+++ b/contrib/llvm/tools/clang/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>;
@@ -337,7 +384,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>;
@@ -346,14 +392,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>;
@@ -367,30 +413,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>;
@@ -399,6 +445,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>;
@@ -414,8 +461,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>;
@@ -426,6 +471,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>;
@@ -437,6 +483,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">;
@@ -447,8 +495,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]>;
@@ -467,9 +516,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>;
@@ -506,17 +557,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">;
@@ -534,7 +590,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]>;
@@ -543,9 +602,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>;
@@ -558,6 +618,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>;
@@ -569,6 +630,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>;
@@ -579,6 +641,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>;
@@ -591,6 +659,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>;
@@ -602,6 +671,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">;
@@ -612,7 +687,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">;
@@ -662,8 +737,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">;
@@ -687,13 +765,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">;
@@ -835,7 +920,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/contrib/llvm/tools/clang/include/clang/Driver/Tool.h b/contrib/llvm/tools/clang/include/clang/Driver/Tool.h
index 378b516..8822d7b 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/Tool.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h b/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h
index 2e6218a..c35cf67 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/ToolChain.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Driver/Types.def b/contrib/llvm/tools/clang/include/clang/Driver/Types.def
index 8449d63..b107dfb 100644
--- a/contrib/llvm/tools/clang/include/clang/Driver/Types.def
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Edit/Commit.h b/contrib/llvm/tools/clang/include/clang/Edit/Commit.h
new file mode 100644
index 0000000..aaf6b18
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h b/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h
new file mode 100644
index 0000000..c685753
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Edit/EditsReceiver.h b/contrib/llvm/tools/clang/include/clang/Edit/EditsReceiver.h
new file mode 100644
index 0000000..600ac28
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Edit/FileOffset.h b/contrib/llvm/tools/clang/include/clang/Edit/FileOffset.h
new file mode 100644
index 0000000..675ad18
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Edit/Rewriters.h b/contrib/llvm/tools/clang/include/clang/Edit/Rewriters.h
new file mode 100644
index 0000000..aa7a5b2
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h b/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h
index 471476a..5e4ecad 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/Analyses.def b/contrib/llvm/tools/clang/include/clang/Frontend/Analyses.def
index 010f889..b5b9394 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/Analyses.def
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/AnalyzerOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/AnalyzerOptions.h
index 3565a51..847bfbd 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/AnalyzerOptions.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h b/contrib/llvm/tools/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h
index f20cf6f..ce2b242 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Serialization/ChainedIncludesSource.h b/contrib/llvm/tools/clang/include/clang/Frontend/ChainedIncludesSource.h
index 620dbdf..d7119e9 100644
--- a/contrib/llvm/tools/clang/include/clang/Serialization/ChainedIncludesSource.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h
index 4874c17..e844f88 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/CodeGenOptions.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h b/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h
index 8817740..1bb7695 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInstance.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h b/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h
index 47c7031..0d2260a 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/CompilerInvocation.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/DependencyOutputOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/DependencyOutputOptions.h
index 1e22c22..83976c3 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/DependencyOutputOptions.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/DiagnosticOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/DiagnosticOptions.h
index 319abeb..1c6ba6a 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/DiagnosticOptions.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/DiagnosticRenderer.h b/contrib/llvm/tools/clang/include/clang/Frontend/DiagnosticRenderer.h
new file mode 100644
index 0000000..5ad88a8
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/FrontendAction.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendAction.h
index f85cc7e..6839028 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendAction.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h
index 72a3d90..8817c5a 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendActions.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/FrontendDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendDiagnostic.h
index 21cd2c6..0b05b74 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendDiagnostic.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h
index fa6d044..a051d7f 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/FrontendOptions.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h
index de2800c..e6f4403 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandard.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def b/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def
index c82290b..4bcff4a 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/LangStandards.def
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/LayoutOverrideSource.h b/contrib/llvm/tools/clang/include/clang/Frontend/LayoutOverrideSource.h
new file mode 100644
index 0000000..225efe6
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/MigratorOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/MigratorOptions.h
new file mode 100644
index 0000000..f9554e4
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/MultiplexConsumer.h b/contrib/llvm/tools/clang/include/clang/Frontend/MultiplexConsumer.h
index 4242f01..ffa7b4a 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/MultiplexConsumer.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/PreprocessorOptions.h b/contrib/llvm/tools/clang/include/clang/Frontend/PreprocessorOptions.h
index 0ee8cb3..d86a923 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/PreprocessorOptions.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h b/contrib/llvm/tools/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h
new file mode 100644
index 0000000..aa0695f
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnostic.h
new file mode 100644
index 0000000..519d3b6
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnosticPrinter.h b/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnosticPrinter.h
index 22fa18b..9b6ac24 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/Utils.h b/contrib/llvm/tools/clang/include/clang/Frontend/Utils.h
index 929beb0..6b1fc63 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/Utils.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h b/contrib/llvm/tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
index 28dc9de..2fc6ccc 100644
--- a/contrib/llvm/tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Index/ASTLocation.h b/contrib/llvm/tools/clang/include/clang/Index/ASTLocation.h
index 7b66e7e..45097cc 100644
--- a/contrib/llvm/tools/clang/include/clang/Index/ASTLocation.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Index/CallGraph.h b/contrib/llvm/tools/clang/include/clang/Index/GlobalCallGraph.h
index 38baf0f..7ba1cce 100644
--- a/contrib/llvm/tools/clang/include/clang/Index/CallGraph.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Lex/DirectoryLookup.h b/contrib/llvm/tools/clang/include/clang/Lex/DirectoryLookup.h
index f7da61b..95f0d27 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/DirectoryLookup.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Lex/ExternalPreprocessorSource.h b/contrib/llvm/tools/clang/include/clang/Lex/ExternalPreprocessorSource.h
index dbf7389..f172b5c 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/ExternalPreprocessorSource.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h b/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h
index 84d59f7..5128ce6 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/HeaderSearch.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Lex/LexDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Lex/LexDiagnostic.h
index f454e23..41b9396 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/LexDiagnostic.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Lex/Lexer.h b/contrib/llvm/tools/clang/include/clang/Lex/Lexer.h
index e01427f..04bcead 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/Lexer.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Lex/LiteralSupport.h b/contrib/llvm/tools/clang/include/clang/Lex/LiteralSupport.h
index b33092c..7e7f82f 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/LiteralSupport.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h b/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h
index b381e0f..8775d39 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/MacroInfo.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h b/contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h
index 72ec0e3..36d03c0 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/ModuleLoader.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Lex/ModuleMap.h b/contrib/llvm/tools/clang/include/clang/Lex/ModuleMap.h
new file mode 100644
index 0000000..4ebb1d4
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h b/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h
index 1fc1a05..33558c8 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/PPCallbacks.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h
index 53da19e..45e3a5d 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessingRecord.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h b/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h
index 8b77433..055008f 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h
index e2e30bf..b551cd4 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorLexer.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Lex/Token.h b/contrib/llvm/tools/clang/include/clang/Lex/Token.h
index e6dd160..a88f607 100644
--- a/contrib/llvm/tools/clang/include/clang/Lex/Token.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Parse/ParseAST.h b/contrib/llvm/tools/clang/include/clang/Parse/ParseAST.h
index 7253870..2405a0c 100644
--- a/contrib/llvm/tools/clang/include/clang/Parse/ParseAST.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Parse/ParseDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Parse/ParseDiagnostic.h
index 0e76c61..0d47292 100644
--- a/contrib/llvm/tools/clang/include/clang/Parse/ParseDiagnostic.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Parse/Parser.h b/contrib/llvm/tools/clang/include/clang/Parse/Parser.h
index 0046f88..dff8510 100644
--- a/contrib/llvm/tools/clang/include/clang/Parse/Parser.h
+++ b/contrib/llvm/tools/clang/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 = 512 };
+
+ 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/contrib/llvm/tools/clang/include/clang/Rewrite/ASTConsumers.h b/contrib/llvm/tools/clang/include/clang/Rewrite/ASTConsumers.h
index 7a636e5..c9c92e3 100644
--- a/contrib/llvm/tools/clang/include/clang/Rewrite/ASTConsumers.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Rewrite/FixItRewriter.h b/contrib/llvm/tools/clang/include/clang/Rewrite/FixItRewriter.h
index bf7e791..44f0611 100644
--- a/contrib/llvm/tools/clang/include/clang/Rewrite/FixItRewriter.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Rewrite/FrontendActions.h b/contrib/llvm/tools/clang/include/clang/Rewrite/FrontendActions.h
index f7aeefa..6e9ecac 100644
--- a/contrib/llvm/tools/clang/include/clang/Rewrite/FrontendActions.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Rewrite/TokenRewriter.h b/contrib/llvm/tools/clang/include/clang/Rewrite/TokenRewriter.h
index 62ea12a..9ebd33a 100644
--- a/contrib/llvm/tools/clang/include/clang/Rewrite/TokenRewriter.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h b/contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h
index bcacf7a..142f144 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/AttributeList.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteConsumer.h b/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteConsumer.h
index 9e2d60d..fe9bed5 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/CodeCompleteConsumer.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h b/contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h
index 3260a70..67fd393 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/DeclSpec.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/DelayedDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Sema/DelayedDiagnostic.h
index dd2603d..3320cd8 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/DelayedDiagnostic.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/ExternalSemaSource.h b/contrib/llvm/tools/clang/include/clang/Sema/ExternalSemaSource.h
index 7b83625..785bf6a 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/ExternalSemaSource.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/IdentifierResolver.h b/contrib/llvm/tools/clang/include/clang/Sema/IdentifierResolver.h
index 85d8ad2..dff0134 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/IdentifierResolver.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/Initialization.h b/contrib/llvm/tools/clang/include/clang/Sema/Initialization.h
index e69bebd..4433843 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/Initialization.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/LocInfoType.h b/contrib/llvm/tools/clang/include/clang/Sema/LocInfoType.h
index e1d3ae9..93cb8cb 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/LocInfoType.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/Lookup.h b/contrib/llvm/tools/clang/include/clang/Sema/Lookup.h
index 6630bb2..fe5d262 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/Lookup.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/MultiInitializer.h b/contrib/llvm/tools/clang/include/clang/Sema/MultiInitializer.h
deleted file mode 100644
index c44e393..0000000
--- a/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/Overload.h b/contrib/llvm/tools/clang/include/clang/Sema/Overload.h
index dbc0926..d334447 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/Overload.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/ParsedTemplate.h b/contrib/llvm/tools/clang/include/clang/Sema/ParsedTemplate.h
index 735a26b..3ff0459 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/ParsedTemplate.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/PrettyDeclStackTrace.h b/contrib/llvm/tools/clang/include/clang/Sema/PrettyDeclStackTrace.h
index a31312c..aa55705 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/PrettyDeclStackTrace.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/Scope.h b/contrib/llvm/tools/clang/include/clang/Sema/Scope.h
index cff8b33..e9aa173 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/Scope.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h b/contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h
index 9ef6d3c..ceaf586 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/ScopeInfo.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/Sema.h b/contrib/llvm/tools/clang/include/clang/Sema/Sema.h
index 22d5db2..31c410a 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/Sema.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/SemaConsumer.h b/contrib/llvm/tools/clang/include/clang/Sema/SemaConsumer.h
index 3689a6e..139cce8 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/SemaConsumer.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/SemaDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Sema/SemaDiagnostic.h
index 2c4bf4b..9605bf8 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/SemaDiagnostic.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/SemaFixItUtils.h b/contrib/llvm/tools/clang/include/clang/Sema/SemaFixItUtils.h
index 0c1bba5..fffca67 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/SemaFixItUtils.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/Template.h b/contrib/llvm/tools/clang/include/clang/Sema/Template.h
index 78f50fa..c16823a 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/Template.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/TemplateDeduction.h b/contrib/llvm/tools/clang/include/clang/Sema/TemplateDeduction.h
index 690129a..100d56e 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/TemplateDeduction.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Sema/TypoCorrection.h b/contrib/llvm/tools/clang/include/clang/Sema/TypoCorrection.h
index 9537c30..a8f6e11 100644
--- a/contrib/llvm/tools/clang/include/clang/Sema/TypoCorrection.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h b/contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h
index 494835c..4591630 100644
--- a/contrib/llvm/tools/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/contrib/llvm/tools/clang/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,28 +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 = 9
+ SPECIAL_TYPE_UCONTEXT_T = 8
};
/// \brief The number of special type IDs.
- const unsigned NumSpecialTypeIDs = 0;
+ const unsigned NumSpecialTypeIDs = 9;
/// \brief Predefined declaration IDs.
///
@@ -706,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.
///
@@ -752,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.
@@ -859,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.
@@ -875,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.
@@ -973,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,
@@ -984,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.
@@ -994,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.
@@ -1017,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++
@@ -1045,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
@@ -1075,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
@@ -1097,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
@@ -1123,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/contrib/llvm/tools/clang/include/clang/Serialization/ASTDeserializationListener.h b/contrib/llvm/tools/clang/include/clang/Serialization/ASTDeserializationListener.h
index 588fe0e..ab0d313 100644
--- a/contrib/llvm/tools/clang/include/clang/Serialization/ASTDeserializationListener.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h b/contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h
index 996a134..9baaf4b 100644
--- a/contrib/llvm/tools/clang/include/clang/Serialization/ASTReader.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h b/contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h
index 7a49e48..4c62385 100644
--- a/contrib/llvm/tools/clang/include/clang/Serialization/ASTWriter.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Serialization/ContinuousRangeMap.h b/contrib/llvm/tools/clang/include/clang/Serialization/ContinuousRangeMap.h
index 7f78320..f368a80 100644
--- a/contrib/llvm/tools/clang/include/clang/Serialization/ContinuousRangeMap.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Serialization/Module.h b/contrib/llvm/tools/clang/include/clang/Serialization/Module.h
index 42b5a58..4c93c33 100644
--- a/contrib/llvm/tools/clang/include/clang/Serialization/Module.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h b/contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h
index f86915a..6ff0640 100644
--- a/contrib/llvm/tools/clang/include/clang/Serialization/ModuleManager.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Serialization/SerializationDiagnostic.h b/contrib/llvm/tools/clang/include/clang/Serialization/SerializationDiagnostic.h
new file mode 100644
index 0000000..e63f814
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/CommonBugCategories.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Checkers/CommonBugCategories.h
new file mode 100644
index 0000000..9d4251b
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index bfb7ef8..2b699a8 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
index 41c0a3a..7e665ce 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
index 78067cd..cb49122 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index 406be3c..5a8a1c7 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Checker.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Checker.h
index 1e4edeb..76d8c15 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
index e3e4c49..d215f99 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
index b59c14d..1452d45 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
index d1f5a7d..65be3a4 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index 6c93f59..3cbecf7 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index 42a1537..9a699f9 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index 1f14787..b051d33 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index 3f6ddde..631858d 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 131d39e..59136fc 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
index 2463e23..b80213e 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index fdfed3d..46fbb88 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 9bc470f..2a21a03 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h
deleted file mode 100644
index 89b47dc..0000000
--- a/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
new file mode 100644
index 0000000..42adff3
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index c9941fe..87bc0df 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
index add3479..d8aec09 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index edae06e..360d648 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
index b80d494..1c7bedb 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h
new file mode 100644
index 0000000..371f3c5
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 17233e1..4ad36f9 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 5827b00..ed01db2 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index a688d7f..5315f4b 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index ae212bc..baf57d4 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 0d6e18e..c7de7ef 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
new file mode 100644
index 0000000..53205d3
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h
new file mode 100644
index 0000000..8ddc8b9d
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
index fa34075..51aa753 100644
--- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabase.h b/contrib/llvm/tools/clang/include/clang/Tooling/CompilationDatabase.h
new file mode 100644
index 0000000..3430320
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/include/clang/Tooling/Tooling.h b/contrib/llvm/tools/clang/include/clang/Tooling/Tooling.h
new file mode 100644
index 0000000..868eae3
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMT.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMT.cpp
index 6e1b0e5..9354dc3 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMT.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMTActions.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMTActions.cpp
index dea867a..0ed36dd 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/ARCMTActions.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/FileRemapper.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/FileRemapper.cpp
index c6e6ce4..474ce7d 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/FileRemapper.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/Internals.h b/contrib/llvm/tools/clang/lib/ARCMigrate/Internals.h
index 46f3bb6..59177c4 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/Internals.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/ObjCMT.cpp
new file mode 100644
index 0000000..e635274
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/TransARCAssign.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransARCAssign.cpp
index 1f10196..cfa6da1 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransARCAssign.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/TransAutoreleasePool.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransAutoreleasePool.cpp
index 08561f9..8787724 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransAutoreleasePool.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp
index 48c0ca9..3be8132 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
index 3ad05e6..0fb7141 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/TransGCAttrs.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransGCAttrs.cpp
new file mode 100644
index 0000000..9f6066e
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/TransGCCalls.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransGCCalls.cpp
new file mode 100644
index 0000000..1be9020
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp
index ca845b6..cc85fe2 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
index 394f848..11a6553 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp
index 69fb2e8..48437c7 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnusedInitDelegate.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnusedInitDelegate.cpp
index e2aa6ff..60ed32a 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransUnusedInitDelegate.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
index 1dbe811..d1f08aa 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp
index ec676e9..0ecfeb5 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransformActions.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.cpp
index 4244faf..d342d1a 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.h b/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.h
index 5e4db56..445c3e5 100644
--- a/contrib/llvm/tools/clang/lib/ARCMigrate/Transforms.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/APValue.cpp b/contrib/llvm/tools/clang/lib/AST/APValue.cpp
index 6f63a32..a31b3c5 100644
--- a/contrib/llvm/tools/clang/lib/AST/APValue.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ASTConsumer.cpp b/contrib/llvm/tools/clang/lib/AST/ASTConsumer.cpp
index 04a084a..1672bc8 100644
--- a/contrib/llvm/tools/clang/lib/AST/ASTConsumer.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp
index 0833286..acf5e0b 100644
--- a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp
+++ b/contrib/llvm/tools/clang/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,13 +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), ucontext_tDecl(0),
BlockDescriptorType(0), BlockDescriptorExtendedType(0),
cudaConfigureCallDecl(0),
- NullTypeSourceInfo(QualType()),
+ NullTypeSourceInfo(QualType()),
+ FirstLocalImport(), LastLocalImport(),
SourceMgr(SM), LangOpts(LOpts),
AddrSpaceMap(0), Target(t), PrintingPolicy(LOpts),
Idents(idents), Selectors(sels),
@@ -258,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*,
@@ -291,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());
}
@@ -331,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";
@@ -462,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);
@@ -476,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
@@ -676,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
//===----------------------------------------------------------------------===//
@@ -796,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()) {
@@ -813,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:
@@ -832,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;
@@ -1134,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;
@@ -1173,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);
}
}
@@ -1194,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);
@@ -1203,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);
@@ -1226,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
@@ -1256,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) {
@@ -1337,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);
@@ -1640,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 =
@@ -1667,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)
@@ -1786,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
@@ -1803,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)
@@ -1850,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.
@@ -1860,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);
@@ -1869,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
@@ -1904,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 =
@@ -2082,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;
@@ -2101,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
@@ -2162,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));
@@ -2188,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 =
@@ -2226,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);
@@ -2239,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);
@@ -2374,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());
@@ -2400,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,
@@ -2411,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);
}
@@ -2430,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);
@@ -2448,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())
@@ -2677,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;
}
@@ -2690,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;
@@ -2775,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;
@@ -2833,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:
@@ -2896,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);
@@ -2913,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);
}
@@ -2996,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 {
@@ -3010,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));
@@ -3047,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.
@@ -3063,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(),
@@ -3121,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) {
@@ -3243,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()));
@@ -3317,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()));
}
@@ -3346,8 +3406,7 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
return NNS;
}
- // Required to silence a GCC warning
- return 0;
+ llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
}
@@ -3372,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;
@@ -3462,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);
@@ -3508,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;
@@ -3517,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
@@ -3544,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");
@@ -3625,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);
@@ -3697,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);
@@ -3832,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();
@@ -3857,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;
@@ -4037,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!
@@ -4083,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);
}
@@ -4113,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
@@ -4293,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()));
@@ -4312,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);
@@ -4491,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;
}
@@ -4538,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 += '"';
@@ -4567,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(),
@@ -4780,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);
@@ -4798,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!");
@@ -4987,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
@@ -5059,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)
@@ -5360,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 {
@@ -5484,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();
@@ -5791,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();
}
@@ -5959,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>(),
@@ -5967,10 +6111,10 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
return LHS;
return QualType();
- }
+ }
}
- return QualType();
+ llvm_unreachable("Invalid Type::Class!");
}
bool ASTContext::FunctionTypesMatchOnNSConsumedAttrs(
@@ -6333,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;
}
}
@@ -6425,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())
@@ -6457,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;
@@ -6485,7 +6632,7 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
}
}
- return GVA_StrongExternal;
+ llvm_unreachable("Invalid Linkage!");
}
bool ASTContext::DeclMustBeEmitted(const Decl *D) {
@@ -6602,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/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp b/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp
index 07820dc..ca4fe26 100644
--- a/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp
index af66b04..3879907 100644
--- a/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/AttrImpl.cpp b/contrib/llvm/tools/clang/lib/AST/AttrImpl.cpp
index 3ca7d4d..cffcc65 100644
--- a/contrib/llvm/tools/clang/lib/AST/AttrImpl.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp b/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp
index f29bfd1..2186730 100644
--- a/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/Decl.cpp b/contrib/llvm/tools/clang/lib/AST/Decl.cpp
index 95d52cb..399f2e4 100644
--- a/contrib/llvm/tools/clang/lib/AST/Decl.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp
index 321e40b..47a0d25 100644
--- a/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp b/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp
index f3da67c..114322b 100644
--- a/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/DeclFriend.cpp b/contrib/llvm/tools/clang/lib/AST/DeclFriend.cpp
index 99bfe40..6e3bd8d 100644
--- a/contrib/llvm/tools/clang/lib/AST/DeclFriend.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp b/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp
index a589b7f..2370d3c 100644
--- a/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp b/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp
index 08a1ab5..74e1c1b 100644
--- a/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp b/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp
index 558a4cc..4590195 100644
--- a/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp b/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp
index bf647ed..64924ad 100644
--- a/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp b/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp
index 2568ada..4c7cd8a 100644
--- a/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/Expr.cpp b/contrib/llvm/tools/clang/lib/AST/Expr.cpp
index b0bcfe0..868109e 100644
--- a/contrib/llvm/tools/clang/lib/AST/Expr.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp b/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp
index ad5ec8b..8cf519c 100644
--- a/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp b/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp
index 49c6821..b091e19 100644
--- a/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp
index df75bc8..01c9fe7 100644
--- a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp b/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp
index acedf70..d7b6354 100644
--- a/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/LambdaMangleContext.cpp b/contrib/llvm/tools/clang/lib/AST/LambdaMangleContext.cpp
new file mode 100644
index 0000000..f5272a7
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/Mangle.cpp b/contrib/llvm/tools/clang/lib/AST/Mangle.cpp
index 5cb8f47..73c9f57 100644
--- a/contrib/llvm/tools/clang/lib/AST/Mangle.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp b/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp
index 1515db4..ba9856a 100644
--- a/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/NSAPI.cpp b/contrib/llvm/tools/clang/lib/AST/NSAPI.cpp
new file mode 100644
index 0000000..f5ea2c5
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp b/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp
index 1ff2e71..dbf267b 100644
--- a/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ParentMap.cpp b/contrib/llvm/tools/clang/lib/AST/ParentMap.cpp
index 5eef83a..64016d9 100644
--- a/contrib/llvm/tools/clang/lib/AST/ParentMap.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/RecordLayout.cpp b/contrib/llvm/tools/clang/lib/AST/RecordLayout.cpp
index ccc591a..0114eba 100644
--- a/contrib/llvm/tools/clang/lib/AST/RecordLayout.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp b/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp
index bbd3fc0..c2d9294 100644
--- a/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/Stmt.cpp b/contrib/llvm/tools/clang/lib/AST/Stmt.cpp
index e7b87e4..6af20df 100644
--- a/contrib/llvm/tools/clang/lib/AST/Stmt.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/StmtDumper.cpp b/contrib/llvm/tools/clang/lib/AST/StmtDumper.cpp
index 2968739..b5e298c 100644
--- a/contrib/llvm/tools/clang/lib/AST/StmtDumper.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp b/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp
index daaa354..3a44183 100644
--- a/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp b/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp
index 214378a..e5526ce 100644
--- a/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp b/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp
index 0c011a8..531e03e 100644
--- a/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp b/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp
index a0487ba..e89ba53 100644
--- a/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/Type.cpp b/contrib/llvm/tools/clang/lib/AST/Type.cpp
index 44eeec0..c82aeaa 100644
--- a/contrib/llvm/tools/clang/lib/AST/Type.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp b/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp
index 8e8b227..caa19b1 100644
--- a/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp b/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp
index fb7b918..3bf80e7 100644
--- a/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/VTableBuilder.cpp b/contrib/llvm/tools/clang/lib/AST/VTableBuilder.cpp
index 7765817..7a45972 100644
--- a/contrib/llvm/tools/clang/lib/AST/VTableBuilder.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/AnalysisContext.cpp b/contrib/llvm/tools/clang/lib/Analysis/AnalysisDeclContext.cpp
index 3dd194b..659cc6d 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/AnalysisContext.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp
index 83c7384..d1334a5 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp b/contrib/llvm/tools/clang/lib/Analysis/CallGraph.cpp
new file mode 100644
index 0000000..96a16c3
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp b/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp
index 8acd189..7e9e38f 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/Dominators.cpp b/contrib/llvm/tools/clang/lib/Analysis/Dominators.cpp
new file mode 100644
index 0000000..0e02c6d
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/FormatString.cpp b/contrib/llvm/tools/clang/lib/Analysis/FormatString.cpp
index a26f0ad..51fac49 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/FormatString.cpp
+++ b/contrib/llvm/tools/clang/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,52 @@ 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 "@";
+
+ // FreeBSD specific specifiers.
+ case bArg: return "b";
+ case DArg: return "D";
+ case rArg: return "r";
+
+ // GlibC specific specifiers.
+ case PrintErrno: return "m";
+ }
+ return NULL;
+}
+
+//===----------------------------------------------------------------------===//
// Methods on OptionalAmount.
//===----------------------------------------------------------------------===//
@@ -398,19 +511,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:
@@ -428,7 +538,7 @@ bool FormatSpecifier::hasValidLengthModifier() const {
return false;
}
- // Handle 'l' flag
+ // Handle 'l' flag
case LengthModifier::AsLong:
switch (CS.getKind()) {
case ConversionSpecifier::dArg:
@@ -449,6 +559,7 @@ bool FormatSpecifier::hasValidLengthModifier() const {
case ConversionSpecifier::cArg:
case ConversionSpecifier::sArg:
case ConversionSpecifier::rArg:
+ case ConversionSpecifier::ScanListArg:
return true;
default:
return false;
@@ -465,11 +576,113 @@ 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::bArg:
+ case ConversionSpecifier::DArg:
+ case ConversionSpecifier::rArg:
+ 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/contrib/llvm/tools/clang/lib/Analysis/FormatStringParsing.h b/contrib/llvm/tools/clang/lib/Analysis/FormatStringParsing.h
index 607e99c..f483ec6 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/FormatStringParsing.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp b/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp
index 62c5455..ff6607d 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/LiveVariables.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/PostOrderCFGView.cpp b/contrib/llvm/tools/clang/lib/Analysis/PostOrderCFGView.cpp
new file mode 100644
index 0000000..cfd66f7
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp b/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp
index 2bb39cf..4b2a19e 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp
+++ b/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp
@@ -52,7 +52,7 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
const char *&Beg,
const char *E,
unsigned &argIndex,
- bool FormatExtensions) {
+ const LangOptions &LO) {
using namespace clang::analyze_format_string;
using namespace clang::analyze_printf;
@@ -151,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;
@@ -197,10 +197,10 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
// Glibc specific.
case 'm': k = ConversionSpecifier::PrintErrno; break;
// FreeBSD format extensions
- case 'b': if (FormatExtensions) k = ConversionSpecifier::bArg; break; /* check for int and then char * */
- case 'r': if (FormatExtensions) k = ConversionSpecifier::rArg; break;
- case 'y': if (FormatExtensions) k = ConversionSpecifier::iArg; break;
- case 'D': if (FormatExtensions) k = ConversionSpecifier::DArg; break; /* check for u_char * pointer and a char * string */
+ case 'b': if (LO.FormatExtensions) k = ConversionSpecifier::bArg; break; /* check for int and then char * */
+ case 'r': if (LO.FormatExtensions) k = ConversionSpecifier::rArg; break;
+ case 'y': if (LO.FormatExtensions) k = ConversionSpecifier::iArg; break;
+ case 'D': if (LO.FormatExtensions) k = ConversionSpecifier::DArg; break; /* check for u_char * pointer and a char * string */
}
PrintfConversionSpecifier CS(conversionPosition, k);
FS.setConversionSpecifier(CS);
@@ -220,14 +220,14 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,
const char *I,
const char *E,
- bool FormatExtensions) {
+ 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,
- FormatExtensions);
+ 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())
@@ -246,55 +246,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 "@";
-
- // FreeBSD specific specifiers.
- case bArg: return "b";
- case DArg: return "D";
- case rArg: return "r";
-
- // 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())
@@ -303,7 +259,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();
}
@@ -311,39 +268,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()) {
@@ -354,15 +322,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;
}
@@ -371,7 +348,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);
@@ -383,16 +361,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()) {
@@ -404,18 +382,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;
@@ -453,6 +428,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()) {
@@ -472,9 +469,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/contrib/llvm/tools/clang/lib/Analysis/ProgramPoint.cpp b/contrib/llvm/tools/clang/lib/Analysis/ProgramPoint.cpp
index 3a0bbd5..3f711b4 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/ProgramPoint.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/PseudoConstantAnalysis.cpp b/contrib/llvm/tools/clang/lib/Analysis/PseudoConstantAnalysis.cpp
index 8f24c43..c8b491a 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/PseudoConstantAnalysis.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp b/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp
index 4931771..bb63e2c 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp b/contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp
index 6a8673a..6bc4adb 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/ScanfFormatString.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp b/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp
index 5a12913..2f7e794 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/ThreadSafety.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp b/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp
index 9e98560..6e5da25 100644
--- a/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp b/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp
index 7bdcdc6..c78a292 100644
--- a/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/ConvertUTF.c b/contrib/llvm/tools/clang/lib/Basic/ConvertUTF.c
index 124e386..e197003 100644
--- a/contrib/llvm/tools/clang/lib/Basic/ConvertUTF.c
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp
index e5f3901..f7d5d87 100644
--- a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp
index 9481287..8c33a96 100644
--- a/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp
index c1f715e..fd6d334 100644
--- a/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/FileSystemStatCache.cpp b/contrib/llvm/tools/clang/lib/Basic/FileSystemStatCache.cpp
index c8b07af..875d397 100644
--- a/contrib/llvm/tools/clang/lib/Basic/FileSystemStatCache.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp
index 38f09a0..43899f0 100644
--- a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/LangOptions.cpp b/contrib/llvm/tools/clang/lib/Basic/LangOptions.cpp
index 5f479db..991992a 100644
--- a/contrib/llvm/tools/clang/lib/Basic/LangOptions.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/Module.cpp b/contrib/llvm/tools/clang/lib/Basic/Module.cpp
new file mode 100644
index 0000000..6348840
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp
index 6e4f3e6..bb5a10a 100644
--- a/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp
index 364663e..cef091c 100644
--- a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp
index 593db2b..f938b5a 100644
--- a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/Targets.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp
index ae5f270..1ad37c4 100644
--- a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp
+++ b/contrib/llvm/tools/clang/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
@@ -249,7 +246,7 @@ protected:
unsigned Release = Triple.getOSMajorVersion();
if (Release == 0U)
- Release = 8U;
+ Release = 8;
Builder.defineMacro("__FreeBSD__", Twine(Release));
Builder.defineMacro("__FreeBSD_cc_version", Twine(Release * 100000U + 1U));
@@ -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
@@ -1283,6 +1363,20 @@ class X86TargetInfo : public TargetInfo {
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.
@@ -1300,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;
@@ -1332,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)
@@ -1367,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)
@@ -1383,6 +1489,9 @@ public:
.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);
@@ -1436,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:
@@ -1444,6 +1554,9 @@ public:
case CK_Opteron:
case CK_OpteronSSE3:
case CK_AMDFAM10:
+ case CK_BTVER1:
+ case CK_BDVER1:
+ case CK_BDVER2:
case CK_x86_64:
return true;
}
@@ -1465,6 +1578,12 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
Features["sse4a"] = false;
Features["aes"] = false;
Features["avx"] = 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.
@@ -1509,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);
@@ -1528,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);
@@ -1567,6 +1694,15 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
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);
@@ -1575,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.
@@ -1600,7 +1736,8 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
Features["ssse3"] = true;
else if (Name == "sse4" || Name == "sse4.2")
Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
- Features["ssse3"] = Features["sse41"] = Features["sse42"] = true;
+ Features["ssse3"] = Features["sse41"] = Features["sse42"] =
+ Features["popcnt"] = true;
else if (Name == "sse4.1")
Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = Features["sse41"] = true;
@@ -1613,21 +1750,39 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
else if (Name == "avx")
Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = Features["sse41"] = Features["sse42"] =
- Features["avx"] = true;
+ 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["sse4a"] = true;
+ 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")
@@ -1641,9 +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;
@@ -1658,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)
@@ -1682,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)
@@ -1705,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");
@@ -1729,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__");
@@ -1739,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:
@@ -1768,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__");
@@ -1811,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__");
@@ -1836,19 +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:
- Builder.defineMacro("__amdfam10");
- Builder.defineMacro("__amdfam10__");
- Builder.defineMacro("__tune_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;
}
@@ -1864,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:
@@ -1889,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:
@@ -1917,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,
@@ -1959,7 +2176,6 @@ X86TargetInfo::validateAsmConstraint(const char *&Name,
// x86_64 instructions.
return true;
}
- return false;
}
@@ -1992,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";
@@ -2023,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) :
@@ -2041,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-"
@@ -2233,6 +2465,7 @@ public:
LongDoubleAlign = 128;
LargeArrayMinWidth = 128;
LargeArrayAlign = 128;
+ SuitableAlign = 128;
IntMaxType = SignedLong;
UIntMaxType = UnsignedLong;
Int64Type = SignedLong;
@@ -2245,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
@@ -2399,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.
@@ -2426,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) {
@@ -2436,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.
@@ -2485,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;
@@ -2522,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")
@@ -2540,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);
}
@@ -2606,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;";
}
@@ -2729,7 +2983,6 @@ const Builtin::Info ARMTargetInfo::BuiltinInfo[] = {
};
} // end anonymous namespace.
-
namespace {
class DarwinARMTargetInfo :
public DarwinTargetInfo<ARMTargetInfo> {
@@ -2750,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[];
@@ -2758,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;
@@ -2786,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!
@@ -2887,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;
@@ -2912,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,
@@ -2947,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
@@ -3107,6 +3388,7 @@ namespace {
IntAlign = 32;
LongAlign = LongLongAlign = 32;
PointerAlign = 32;
+ SuitableAlign = 32;
SizeType = UnsignedInt;
IntMaxType = SignedLong;
UIntMaxType = UnsignedLong;
@@ -3134,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 {
@@ -3156,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) {
@@ -3174,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"
};
@@ -3208,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;
@@ -3237,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");
@@ -3278,8 +3634,8 @@ public:
{ { "k0" }, "$26" },
{ { "k1" }, "$27" },
{ { "gp" }, "$28" },
- { { "sp" }, "$29" },
- { { "fp" }, "$30" },
+ { { "sp","$sp" }, "$29" },
+ { { "fp","$fp" }, "$30" },
{ { "ra" }, "$31" }
};
Aliases = GCCRegAliases;
@@ -3307,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";
}
@@ -3325,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");
@@ -3380,8 +3752,8 @@ public:
{ { "k0" }, "$26" },
{ { "k1" }, "$27" },
{ { "gp" }, "$28" },
- { { "sp" }, "$29" },
- { { "fp" }, "$30" },
+ { { "sp","$sp" }, "$29" },
+ { { "fp","$fp" }, "$30" },
{ { "ra" }, "$31" }
};
Aliases = GCCRegAliases;
@@ -3394,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 {
@@ -3418,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 {
@@ -3442,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;
@@ -3477,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 {
}
@@ -3526,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())
@@ -3544,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);
@@ -3676,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);
@@ -3694,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:
@@ -3753,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;
@@ -3821,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/contrib/llvm/tools/clang/lib/Basic/Version.cpp b/contrib/llvm/tools/clang/lib/Basic/Version.cpp
index 526b2b4..36138ac 100644
--- a/contrib/llvm/tools/clang/lib/Basic/Version.cpp
+++ b/contrib/llvm/tools/clang/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();
#ifdef CLANG_VENDOR_SUFFIX
OS << CLANG_VENDOR_SUFFIX;
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ABIInfo.h b/contrib/llvm/tools/clang/lib/CodeGen/ABIInfo.h
index 1381238..2853bc8 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/ABIInfo.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp b/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp
index b9e3ed9..2f44711 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp
index 9694953..27bb4ef 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.h b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.h
index 6e71c1f..095cfdb 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp
index ec0ca42..e30b513 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp
index b5e6e0d..7c08650 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp
index 248448c..befebbe 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h
index c2abf35..4e045f5 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp
index 6ae2d0c..4455f1a 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h
index 24ed366..dead7bd 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp
index c28ecc0..6303e20 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp
index b2d0786..b00e2a2 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp
index c7a9b40..7301d20 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h
index a4533a8..ec7705c 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp
index a6147ea..8c154f0 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp
index 3b8f830..10f0b83 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp
index 5e4fb98..95e0030 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGException.h b/contrib/llvm/tools/clang/lib/CodeGen/CGException.h
deleted file mode 100644
index d021616..0000000
--- a/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp
index bd4e553..08970fd 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp
index 97754d5..b6efc1c 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp
index 78db590..d3ba770 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp
index 4a31bcf..0233745 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp
index 3997866..d528e0c 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp
index 3a9fbee..18891f7 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp
index 51f2053..d0aa0f5 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp
index 688e992..db0bd95 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp
index 308e0c7..e5246f1 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp
index ef426ce..9370096 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h
index 4fa47a7..ccf4d4d 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGRTTI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGRTTI.cpp
index fbdb298..19973b4 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGRTTI.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 6475cca..1193e97 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp
index c56931b..bf42dcb 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGTemporaries.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGTemporaries.cpp
deleted file mode 100644
index 0387dae..0000000
--- a/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp
index ea7b8cb..98be872 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp
index a306c85..17a0537 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGValue.h b/contrib/llvm/tools/clang/lib/CodeGen/CGValue.h
index 489e600..ac704e7 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGValue.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp
index 68dd5c9..dd32167 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp
index 8191f02..06e90b6 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h
index 157623d..3e0cd14 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp
index 275045c..c0ccf4d 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h
index dbc6a87..38f5008 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp
index 887c1ea..9ee3f1d 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h
index 9fe51fb..8e08498 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp
index e0d9218..41fd536 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h
index 7f0f8ac..ba2b3ae 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp
index c3f635a..98f67f3 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index e200e79..825e041 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp b/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp
index 793ee91..ea2389e 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/ModuleBuilder.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp
index e1dc8f7..3ed1778 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h
index 8f90c7b..88b4997 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/Action.cpp b/contrib/llvm/tools/clang/lib/Driver/Action.cpp
index 52c0dbb..d7b4bc7 100644
--- a/contrib/llvm/tools/clang/lib/Driver/Action.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/Arg.cpp b/contrib/llvm/tools/clang/lib/Driver/Arg.cpp
index 39b7e55..c0a2a50 100644
--- a/contrib/llvm/tools/clang/lib/Driver/Arg.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/ArgList.cpp b/contrib/llvm/tools/clang/lib/Driver/ArgList.cpp
index ca9b944..55a0ddf 100644
--- a/contrib/llvm/tools/clang/lib/Driver/ArgList.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/CC1AsOptions.cpp b/contrib/llvm/tools/clang/lib/Driver/CC1AsOptions.cpp
index 90c69ff..ea80f5a 100644
--- a/contrib/llvm/tools/clang/lib/Driver/CC1AsOptions.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/CC1Options.cpp b/contrib/llvm/tools/clang/lib/Driver/CC1Options.cpp
index 14cf090..884b363 100644
--- a/contrib/llvm/tools/clang/lib/Driver/CC1Options.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp
index d02da95..42c8449 100644
--- a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/Driver.cpp b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp
index 4e2d7b6..40e0c00 100644
--- a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp b/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp
index f2d9af8..715819d 100644
--- a/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/HostInfo.cpp b/contrib/llvm/tools/clang/lib/Driver/HostInfo.cpp
deleted file mode 100644
index 292678b..0000000
--- a/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/Job.cpp b/contrib/llvm/tools/clang/lib/Driver/Job.cpp
index 5443d70..825c86a 100644
--- a/contrib/llvm/tools/clang/lib/Driver/Job.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/Option.cpp b/contrib/llvm/tools/clang/lib/Driver/Option.cpp
index ee1963f..03360ea 100644
--- a/contrib/llvm/tools/clang/lib/Driver/Option.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp
index 9453848..db4d2a8 100644
--- a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp
index 80394ac..fa9ed49 100644
--- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp
+++ b/contrib/llvm/tools/clang/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,16 +33,7 @@
#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
#ifndef CLANG_PREFIX
#define CLANG_PREFIX
@@ -57,56 +43,26 @@ 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 {
@@ -141,12 +97,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.
@@ -225,18 +186,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;
@@ -255,15 +214,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) {
@@ -274,6 +227,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:
@@ -300,8 +254,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)
@@ -344,8 +298,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()) {
@@ -416,9 +373,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
@@ -445,6 +404,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))
@@ -459,6 +428,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");
@@ -540,7 +541,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);
@@ -717,6 +718,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");
@@ -1022,6 +1025,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 {
@@ -1032,8 +1039,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);
@@ -1066,6 +1410,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;
@@ -1101,13 +1446,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);
@@ -1159,8 +1571,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");
}
@@ -1199,26 +1611,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;
+FreeBSD::FreeBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
- if (Triple.getArch() == llvm::Triple::ppc &&
- llvm::Triple(getDriver().DefaultHostTriple).getArch() ==
- llvm::Triple::ppc64)
- Lib32 = true;
-
- if (Lib32) {
- getFilePaths().push_back(CLANG_PREFIX "/usr/lib32");
- } else {
- getFilePaths().push_back(CLANG_PREFIX "/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 + CLANG_PREFIX "/usr/lib32/crt1.o"))
+ getFilePaths().push_back(getDriver().SysRoot + CLANG_PREFIX "/usr/lib32");
+ else
+ getFilePaths().push_back(getDriver().SysRoot + CLANG_PREFIX "/usr/lib");
}
Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA,
@@ -1254,21 +1657,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");
}
}
@@ -1291,10 +1692,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);
@@ -1306,12 +1707,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,
@@ -1339,8 +1738,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)
@@ -1377,6 +1777,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).
@@ -1392,6 +1828,7 @@ enum LinuxDistro {
Fedora13,
Fedora14,
Fedora15,
+ Fedora16,
FedoraRawhide,
OpenSuse11_3,
OpenSuse11_4,
@@ -1404,62 +1841,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;
@@ -1486,23 +1916,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)
@@ -1514,247 +1940,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
@@ -1771,36 +1956,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");
@@ -1814,13 +2012,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");
@@ -1828,9 +2040,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))
@@ -1842,24 +2052,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);
@@ -1869,22 +2086,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);
}
@@ -1981,6 +2198,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;
@@ -1988,11 +2217,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;
}
@@ -2001,12 +2238,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);
@@ -2029,37 +2272,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
@@ -2068,20 +2284,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());
@@ -2115,322 +2333,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/contrib/llvm/tools/clang/lib/Driver/ToolChains.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h
index 0e4d67c..eaa6be1 100644
--- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/Tools.cpp b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp
index d9423d2..d3dab19 100644
--- a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp
+++ b/contrib/llvm/tools/clang/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.
@@ -1684,9 +2076,28 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fformat_extensions);
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))
@@ -1706,12 +2117,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.
@@ -1748,10 +2154,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.
@@ -1761,6 +2177,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))
@@ -1783,6 +2200,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,
@@ -1796,14 +2224,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.
@@ -1817,10 +2246,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.
@@ -1829,8 +2260,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.
@@ -1868,11 +2303,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);
@@ -1906,8 +2348,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)) {
@@ -1950,10 +2393,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");
}
@@ -1961,6 +2403,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
@@ -1983,7 +2428,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
@@ -2006,7 +2451,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");
@@ -2057,6 +2502,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.
@@ -2086,11 +2532,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))
@@ -2164,6 +2605,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.
@@ -2189,6 +2634,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.
@@ -2237,7 +2688,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 += " ";
@@ -2271,6 +2722,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,
@@ -2307,10 +2776,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.
@@ -2389,6 +2902,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
@@ -2437,12 +2952,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";
@@ -2488,6 +2998,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:
@@ -2510,6 +3169,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(
@@ -2548,13 +3209,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)
@@ -2595,6 +3270,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)
@@ -3000,9 +3676,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";
@@ -3119,7 +3797,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.
@@ -3154,6 +3832,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);
@@ -3185,13 +3865,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.
@@ -3291,8 +3965,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
@@ -3307,9 +3980,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);
@@ -3492,7 +4163,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.
@@ -3513,20 +4184,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);
@@ -3557,8 +4250,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);
@@ -3618,6 +4309,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];
@@ -3631,6 +4325,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,
@@ -3806,8 +4631,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 {
@@ -3832,7 +4661,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
@@ -3841,8 +4673,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");
}
@@ -4062,11 +4898,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");
@@ -4116,8 +4950,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");
}
@@ -4218,12 +5051,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);
@@ -4241,6 +5111,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,
@@ -4290,6 +5184,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");
@@ -4313,6 +5215,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)
@@ -4356,35 +5264,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))
@@ -4394,19 +5303,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)) {
@@ -4423,12 +5321,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));
}
@@ -4452,7 +5344,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));
}
@@ -4472,9 +5364,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);
@@ -4482,33 +5377,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/contrib/llvm/tools/clang/lib/Driver/Tools.h b/contrib/llvm/tools/clang/lib/Driver/Tools.h
index a4f732e..651a8f2 100644
--- a/contrib/llvm/tools/clang/lib/Driver/Tools.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/Types.cpp b/contrib/llvm/tools/clang/lib/Driver/Types.cpp
index d61ab68..50742fe 100644
--- a/contrib/llvm/tools/clang/lib/Driver/Types.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Driver/WindowsToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/WindowsToolChain.cpp
new file mode 100644
index 0000000..6827034
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Edit/Commit.cpp b/contrib/llvm/tools/clang/lib/Edit/Commit.cpp
new file mode 100644
index 0000000..c45ee1f
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp b/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp
new file mode 100644
index 0000000..5b7fa4a
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/contrib/llvm/tools/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
new file mode 100644
index 0000000..24a0db1
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp
index 54bb282..390ae09 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp
index cb195d1..9feb3de 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/ASTMerge.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp
index 032adf3..e32fa63 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp b/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp
index 8195445..58a6b8d 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/ChainedDiagnosticConsumer.cpp b/contrib/llvm/tools/clang/lib/Frontend/ChainedDiagnosticConsumer.cpp
new file mode 100644
index 0000000..c1d3db8
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Serialization/ChainedIncludesSource.cpp b/contrib/llvm/tools/clang/lib/Frontend/ChainedIncludesSource.cpp
index 5fcf11a..dbb06bd 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ChainedIncludesSource.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp
index 5526487..cab6b90 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp
index e926b89..612a0d8 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/contrib/llvm/tools/clang/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)
@@ -684,6 +709,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)
@@ -692,28 +719,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)
@@ -757,77 +787,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!");
@@ -845,43 +868,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);
}
//===----------------------------------------------------------------------===//
@@ -903,10 +917,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)
@@ -914,12 +928,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)) {
@@ -929,12 +944,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)) {
@@ -944,12 +960,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)) {
@@ -959,17 +976,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 =
@@ -983,7 +1034,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,
@@ -1000,25 +1057,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);
@@ -1046,12 +1119,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);
@@ -1061,11 +1139,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);
@@ -1078,6 +1160,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);
@@ -1086,11 +1175,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,
@@ -1103,12 +1196,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);
@@ -1120,7 +1218,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.
@@ -1136,10 +1233,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");
@@ -1149,23 +1249,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);
@@ -1178,16 +1284,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) {
@@ -1249,6 +1371,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:
@@ -1257,6 +1381,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;
}
@@ -1308,8 +1434,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)) {
@@ -1327,12 +1456,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))
@@ -1376,7 +1516,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;
@@ -1457,6 +1597,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),
@@ -1529,7 +1673,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();
@@ -1680,6 +1824,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)
@@ -1704,7 +1849,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);
@@ -1724,6 +1870,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);
@@ -1736,7 +1883,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);
@@ -1753,18 +1902,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,
@@ -1774,13 +1932,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) {
@@ -1806,7 +1965,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);
@@ -1917,45 +2075,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
@@ -1965,6 +2132,8 @@ void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, FileMgr, Diags);
ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args);
ParseTargetArgs(Res.getTargetOpts(), *Args);
+
+ return Success;
}
namespace {
@@ -2024,13 +2193,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/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
index fc15081..b477ade 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp
index ff3a123..21f5daa 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/DependencyGraph.cpp b/contrib/llvm/tools/clang/lib/Frontend/DependencyGraph.cpp
new file mode 100644
index 0000000..eebaf0c
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp b/contrib/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp
new file mode 100644
index 0000000..6c3bb1d
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp
index ba2d63b..da4bdfa 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp
index 6f84da9..b4a439d 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp b/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp
index 3b41d89..79920df 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp
index 1b1c551..7f01cd9 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp
+++ b/contrib/llvm/tools/clang/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"
@@ -30,7 +26,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
+
#ifndef CLANG_PREFIX
#define CLANG_PREFIX
#endif
@@ -112,7 +110,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.
@@ -336,19 +334,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()) {
@@ -391,11 +376,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)
@@ -403,12 +387,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");
@@ -440,6 +429,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
@@ -484,6 +475,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 {
@@ -675,5 +671,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/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp
index 6f49ec4..93d49b0 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp b/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp
index abb521b..f86a574 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/LangStandards.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/LayoutOverrideSource.cpp b/contrib/llvm/tools/clang/lib/Frontend/LayoutOverrideSource.cpp
new file mode 100644
index 0000000..eb7865e
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp
index 8b585be..3fee957 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp b/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp
index 8e746f6..992eeb0 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp
index 8a61f96..9e1587c 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/SerializedDiagnosticPrinter.cpp
new file mode 100644
index 0000000..7bf8742
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnostic.cpp
new file mode 100644
index 0000000..9f5dcb4
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp
index f8ea9f1..57105f1 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticBuffer.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp
index 10e7238..6445a0c 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index cf35c8e..552282d 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp b/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp
index 8fbcd4b..ec5fde0 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/Warnings.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index c9af3cc..2066505 100644
--- a/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/avx2intrin.h b/contrib/llvm/tools/clang/lib/Headers/avx2intrin.h
new file mode 100644
index 0000000..d165f1f
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/avxintrin.h b/contrib/llvm/tools/clang/lib/Headers/avxintrin.h
index 0a0d2e4..7a0ec3f 100644
--- a/contrib/llvm/tools/clang/lib/Headers/avxintrin.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/bmi2intrin.h b/contrib/llvm/tools/clang/lib/Headers/bmi2intrin.h
new file mode 100644
index 0000000..c60b0c4
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/bmiintrin.h b/contrib/llvm/tools/clang/lib/Headers/bmiintrin.h
new file mode 100644
index 0000000..2f7db73
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/cpuid.h b/contrib/llvm/tools/clang/lib/Headers/cpuid.h
new file mode 100644
index 0000000..05c293f
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/emmintrin.h b/contrib/llvm/tools/clang/lib/Headers/emmintrin.h
index 903cfde..e10b77d 100644
--- a/contrib/llvm/tools/clang/lib/Headers/emmintrin.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/float.h b/contrib/llvm/tools/clang/lib/Headers/float.h
index b7cb73a..65b517d 100644
--- a/contrib/llvm/tools/clang/lib/Headers/float.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/fma4intrin.h b/contrib/llvm/tools/clang/lib/Headers/fma4intrin.h
new file mode 100644
index 0000000..c30920d
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/immintrin.h b/contrib/llvm/tools/clang/lib/Headers/immintrin.h
index a19deaa..1605525 100644
--- a/contrib/llvm/tools/clang/lib/Headers/immintrin.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/lzcntintrin.h b/contrib/llvm/tools/clang/lib/Headers/lzcntintrin.h
new file mode 100644
index 0000000..62ab5ca
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/mm3dnow.h b/contrib/llvm/tools/clang/lib/Headers/mm3dnow.h
index 2f456ad..d5236f8 100644
--- a/contrib/llvm/tools/clang/lib/Headers/mm3dnow.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/module.map b/contrib/llvm/tools/clang/lib/Headers/module.map
new file mode 100644
index 0000000..418ba50
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/popcntintrin.h b/contrib/llvm/tools/clang/lib/Headers/popcntintrin.h
new file mode 100644
index 0000000..d439daa
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/smmintrin.h b/contrib/llvm/tools/clang/lib/Headers/smmintrin.h
index 2b8b321..2fab50e 100644
--- a/contrib/llvm/tools/clang/lib/Headers/smmintrin.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/tgmath.h b/contrib/llvm/tools/clang/lib/Headers/tgmath.h
index 1b0b9d2..4fa1cf7 100644
--- a/contrib/llvm/tools/clang/lib/Headers/tgmath.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/tmmintrin.h b/contrib/llvm/tools/clang/lib/Headers/tmmintrin.h
index 07fea1c..a62c6cc 100644
--- a/contrib/llvm/tools/clang/lib/Headers/tmmintrin.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/unwind.h b/contrib/llvm/tools/clang/lib/Headers/unwind.h
new file mode 100644
index 0000000..a065920
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/wmmintrin.h b/contrib/llvm/tools/clang/lib/Headers/wmmintrin.h
index 6b2e468..8f58850 100644
--- a/contrib/llvm/tools/clang/lib/Headers/wmmintrin.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/x86intrin.h b/contrib/llvm/tools/clang/lib/Headers/x86intrin.h
index e5e7a6a..f5e4d88 100644
--- a/contrib/llvm/tools/clang/lib/Headers/x86intrin.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h b/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h
index a0bc0bb..e616157 100644
--- a/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Index/ASTLocation.cpp b/contrib/llvm/tools/clang/lib/Index/ASTLocation.cpp
index 66b393e..fce6099 100644
--- a/contrib/llvm/tools/clang/lib/Index/ASTLocation.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Index/Analyzer.cpp b/contrib/llvm/tools/clang/lib/Index/Analyzer.cpp
index 6be35ab..f77e6ef 100644
--- a/contrib/llvm/tools/clang/lib/Index/Analyzer.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Index/CallGraph.cpp b/contrib/llvm/tools/clang/lib/Index/GlobalCallGraph.cpp
index 741e781..a21b52a 100644
--- a/contrib/llvm/tools/clang/lib/Index/CallGraph.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/HeaderMap.cpp b/contrib/llvm/tools/clang/lib/Lex/HeaderMap.cpp
index 0cb564c..bbfc1df 100644
--- a/contrib/llvm/tools/clang/lib/Lex/HeaderMap.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp
index 931145a..d688e23 100644
--- a/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp b/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp
index a98d889..535a852 100644
--- a/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp b/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp
index 70183fd..c1d228b 100644
--- a/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp b/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp
index 1846d1c..e2b251a 100644
--- a/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp b/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp
index 5a7af56..3d0c9a1 100644
--- a/contrib/llvm/tools/clang/lib/Lex/MacroInfo.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/ModuleMap.cpp b/contrib/llvm/tools/clang/lib/Lex/ModuleMap.cpp
new file mode 100644
index 0000000..5304311
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/PPCaching.cpp b/contrib/llvm/tools/clang/lib/Lex/PPCaching.cpp
index 986341b..6f4c189 100644
--- a/contrib/llvm/tools/clang/lib/Lex/PPCaching.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/PPCallbacks.cpp b/contrib/llvm/tools/clang/lib/Lex/PPCallbacks.cpp
new file mode 100644
index 0000000..952b926
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp b/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp
index de50c75..625a204 100644
--- a/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp b/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp
index 20f624a..7cac63e 100644
--- a/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp b/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp
index 25a98ae..b6689df 100644
--- a/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp b/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp
index e10c95c..fe70585 100644
--- a/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp b/contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp
index e0c4cf0..f104f96 100644
--- a/contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp
index f6532c2..e2a192b 100644
--- a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp b/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp
index 2816609..89d19fd 100644
--- a/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp b/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp
index 31662ad..06e5685 100644
--- a/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp b/contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp
index 0da9ef5..a72bbca 100644
--- a/contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/TokenConcatenation.cpp b/contrib/llvm/tools/clang/lib/Lex/TokenConcatenation.cpp
index dc6d686..84a46ed 100644
--- a/contrib/llvm/tools/clang/lib/Lex/TokenConcatenation.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp b/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp
index a580544..696754c 100644
--- a/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp
index fdd7d0f..d1c2624 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp
index b387e9e..c000f69 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp
index 2aa178f..cf3dca2 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp
index 4339047..b2a65ff 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp
index bc8bbf5..7f3a815 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp
index 60166e8..2af7482 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp
index 33abc93..1c349fd 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp
index 88044d1..789a8ae 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp
index 2ccb6ea..eb13e0d 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h
index 1d3138f..ebb185a 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp
index a2b7cdd..fdb9788 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp
index 3d68a4a..61cd9f2 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp
index d53839f..28c5e8b 100644
--- a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Parse/Parser.cpp b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp
index c909643..054a8fd 100644
--- a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Rewrite/FixItRewriter.cpp b/contrib/llvm/tools/clang/lib/Rewrite/FixItRewriter.cpp
index 632c0de..3863adb 100644
--- a/contrib/llvm/tools/clang/lib/Rewrite/FixItRewriter.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Rewrite/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Rewrite/FrontendActions.cpp
index f00e7fd..1753325 100644
--- a/contrib/llvm/tools/clang/lib/Rewrite/FrontendActions.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Rewrite/HTMLPrint.cpp b/contrib/llvm/tools/clang/lib/Rewrite/HTMLPrint.cpp
index 6a89265..3d190ab 100644
--- a/contrib/llvm/tools/clang/lib/Rewrite/HTMLPrint.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp b/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp
index ba39602..dc39dde 100644
--- a/contrib/llvm/tools/clang/lib/Rewrite/HTMLRewrite.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Rewrite/RewriteMacros.cpp b/contrib/llvm/tools/clang/lib/Rewrite/RewriteMacros.cpp
index d569100..3fa0bdb 100644
--- a/contrib/llvm/tools/clang/lib/Rewrite/RewriteMacros.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Rewrite/RewriteModernObjC.cpp b/contrib/llvm/tools/clang/lib/Rewrite/RewriteModernObjC.cpp
new file mode 100644
index 0000000..57109de
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp b/contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp
index 6a392ea..9c0737f 100644
--- a/contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Rewrite/RewriteTest.cpp b/contrib/llvm/tools/clang/lib/Rewrite/RewriteTest.cpp
index c446324..019e5e7 100644
--- a/contrib/llvm/tools/clang/lib/Rewrite/RewriteTest.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Rewrite/Rewriter.cpp b/contrib/llvm/tools/clang/lib/Rewrite/Rewriter.cpp
index 464b299cc..43fb01b 100644
--- a/contrib/llvm/tools/clang/lib/Rewrite/Rewriter.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp
index babb8af..a8e6791 100644
--- a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp b/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp
index 13a0ede..f142ab4 100644
--- a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp
index da98603..ce9bbb9 100644
--- a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp
index f0a763e..b531acc 100644
--- a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp b/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp
index d6c1ad1..876f9d7 100644
--- a/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp b/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp
index a643267..4d62cab 100644
--- a/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp
index 3e74dfc..ab786c6 100644
--- a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/MultiInitializer.cpp b/contrib/llvm/tools/clang/lib/Sema/MultiInitializer.cpp
deleted file mode 100644
index 8bd2213..0000000
--- a/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/Scope.cpp b/contrib/llvm/tools/clang/lib/Sema/Scope.cpp
index 833a59f..10f12ce 100644
--- a/contrib/llvm/tools/clang/lib/Sema/Scope.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/Sema.cpp b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp
index 533b21c..fcdfcac 100644
--- a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp
index 6cd9230..dea5e76 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp
index 77410db..e935fc7 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 360a040..5a0fcec 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp
index 8bd9351..54683e1 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp
index a6c49bb..fdc2349 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp
+++ b/contrib/llvm/tools/clang/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
@@ -827,7 +1108,9 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) {
DeclRefExpr* NewDRE = DeclRefExpr::Create(
Context,
DRE->getQualifierLoc(),
+ SourceLocation(),
NewBuiltinDecl,
+ /*enclosing*/ false,
DRE->getLocation(),
NewBuiltinDecl->getType(),
DRE->getValueKind());
@@ -1020,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;
}
}
@@ -1204,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();
+ E = E->IgnoreParenCasts();
- 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);
- }
-
- 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;
@@ -1263,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
@@ -1286,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);
}
}
@@ -1327,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;
}
@@ -1354,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.
//
@@ -1400,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();
}
@@ -1427,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();
}
@@ -1453,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);
@@ -1462,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,
@@ -1479,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);
};
}
@@ -1503,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() {
@@ -1545,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());
}
}
}
@@ -1575,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,
@@ -1589,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 {
@@ -1615,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(
@@ -1668,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;
@@ -1688,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;
@@ -1711,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,
@@ -1739,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(
@@ -1753,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
@@ -1777,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;
}
}
@@ -1889,18 +2363,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;
}
@@ -1915,7 +2400,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
@@ -1930,32 +2416,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));
}
}
@@ -1971,10 +2460,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,
@@ -1991,8 +2481,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(
@@ -2027,10 +2518,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;
}
}
@@ -2041,9 +2530,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));
}
}
@@ -2065,13 +2555,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)
@@ -2080,22 +2579,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;
}
@@ -2103,33 +2637,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);
- bool FormatExtensions = getLangOptions().FormatExtensions;
if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
- FormatExtensions))
+ 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 ---------------------------------===//
@@ -2174,16 +2711,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.
@@ -2227,7 +2767,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
@@ -2253,16 +2794,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)
@@ -2324,7 +2878,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);
}
@@ -2366,7 +2920,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());
@@ -2377,6 +2931,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);
@@ -2394,7 +3050,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);
@@ -2561,42 +3217,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:
@@ -2637,6 +3290,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
@@ -2766,12 +3422,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.
@@ -2870,7 +3526,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);
@@ -2882,8 +3539,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);
@@ -2907,7 +3564,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());
}
@@ -2915,19 +3572,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());
@@ -3133,16 +3790,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;
@@ -3157,9 +3814,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);
@@ -3175,7 +3832,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.
@@ -3204,7 +3861,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;
@@ -3230,7 +3887,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());
}
@@ -3238,7 +3895,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())
@@ -3311,8 +3968,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;
@@ -3330,31 +3987,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);
@@ -3367,7 +4023,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());
@@ -3386,16 +4042,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
@@ -3425,11 +4090,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;
@@ -3455,13 +4115,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);
}
@@ -3478,7 +4168,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);
@@ -3502,7 +4192,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)),
@@ -3510,7 +4200,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);
@@ -3520,7 +4210,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();
@@ -3544,8 +4234,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;
}
@@ -3557,24 +4250,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);
}
@@ -3582,7 +4278,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;
@@ -3604,7 +4300,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());
@@ -3620,7 +4316,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,
@@ -3712,8 +4408,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);
}
@@ -3731,7 +4427,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.
@@ -3801,7 +4500,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:
@@ -3897,8 +4596,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;
@@ -3909,21 +4611,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))
@@ -3954,15 +4659,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
@@ -3971,8 +4676,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,
@@ -3982,7 +4701,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;
}
@@ -3992,6 +4711,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)
@@ -4005,7 +4735,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;
}
@@ -4070,7 +4800,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)) {
@@ -4082,22 +4812,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;
}
@@ -4109,7 +4823,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);
@@ -4123,12 +4837,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;
@@ -4137,6 +4845,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;
@@ -4157,11 +4893,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());
@@ -4210,8 +4941,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;
@@ -4228,7 +4965,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);
@@ -4246,7 +4983,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))
@@ -4273,7 +5010,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();
@@ -4281,7 +5030,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();
@@ -4289,7 +5038,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)
@@ -4298,5 +5055,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/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp
index 405d626..1ee7532 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaConsumer.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaConsumer.cpp
new file mode 100644
index 0000000..d83a13e
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp
index d90a821..8b314b5 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp
+++ b/contrib/llvm/tools/clang/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;
}
@@ -1362,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
@@ -1374,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;
@@ -1420,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
@@ -1497,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
@@ -1535,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
@@ -1651,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
@@ -1693,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 {
@@ -1776,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
@@ -1881,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>();
@@ -1926,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
@@ -1940,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()) {
@@ -1987,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.
@@ -2028,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 &&
@@ -2041,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())
@@ -2054,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();
@@ -2085,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.
@@ -2175,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>()) {
@@ -2230,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
@@ -2259,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)
@@ -2315,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
@@ -2357,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:
@@ -2383,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() &&
@@ -2407,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;
}
@@ -2453,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;
@@ -2629,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.
@@ -2683,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());
@@ -2717,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.
@@ -2730,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 {
@@ -2754,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();
@@ -2769,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;
}
@@ -2782,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),
@@ -2790,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();
@@ -2809,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);
@@ -2879,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,
@@ -2897,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;
@@ -3135,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:
@@ -3158,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.
@@ -3169,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;
@@ -3209,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();
}
}
@@ -3289,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();
@@ -3312,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();
@@ -3434,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();
@@ -3548,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);
}
@@ -3606,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();
@@ -3677,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
@@ -3766,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();
@@ -3808,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)
@@ -3817,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);
@@ -3834,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();
}
}
@@ -3858,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(),
@@ -3884,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);
@@ -3905,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
@@ -3971,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).
@@ -3999,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.
@@ -4011,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.
@@ -4204,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);
@@ -4284,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;
}
@@ -4387,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
@@ -4407,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;
@@ -4416,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) {
@@ -4431,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);
@@ -4454,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(),
@@ -4487,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();
@@ -4509,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();
@@ -4524,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:
@@ -4570,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
@@ -4580,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();
@@ -4612,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);
@@ -4624,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);
@@ -4647,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);
@@ -4663,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());
@@ -4699,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());
@@ -4708,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);
}
@@ -4760,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();
@@ -4783,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(),
@@ -4811,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);
@@ -4880,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
@@ -4907,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.
@@ -4919,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.
@@ -4974,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();
}
@@ -5007,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
@@ -5028,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>())
@@ -5077,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) &&
@@ -5135,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.
@@ -5173,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();
@@ -5224,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);
@@ -5235,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);
@@ -5250,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
@@ -5331,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();
}
@@ -5393,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();
@@ -5403,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()) {
@@ -5493,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)
@@ -5514,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;
}
@@ -5524,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");
@@ -5542,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());
@@ -5554,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);
@@ -5633,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);
}
@@ -5786,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);
@@ -5844,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.
@@ -5879,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) {
@@ -5932,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
@@ -5946,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;
}
@@ -5968,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.,
@@ -6014,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
@@ -6042,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())
@@ -6083,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);
}
@@ -6218,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;
@@ -6226,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;
}
@@ -6295,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);
}
@@ -6352,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();
}
}
@@ -6394,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);
}
@@ -6448,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:
@@ -6464,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;
@@ -6480,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),
@@ -6493,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>())
@@ -6586,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);
@@ -6608,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);
@@ -6660,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);
@@ -6715,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();
@@ -6732,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)
@@ -6743,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)
@@ -6758,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()) {
@@ -6826,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";
@@ -6856,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);
@@ -6892,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())
@@ -6911,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);
@@ -6987,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>();
@@ -7068,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()) {
@@ -7096,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);
@@ -7154,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;
@@ -7191,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());
}
@@ -7212,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;
@@ -7230,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),
@@ -7272,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)) {
@@ -7288,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));
@@ -7306,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() ==
@@ -7316,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>())
@@ -7347,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);
@@ -7406,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.
///
@@ -7512,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;
@@ -7576,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();
}
@@ -7686,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
@@ -7697,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();
}
@@ -7708,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;
@@ -7759,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() &&
@@ -7781,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);
}
@@ -7799,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();
@@ -7851,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) {
@@ -7891,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.
@@ -7900,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
@@ -7951,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.
@@ -8033,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.
}
@@ -8043,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);
@@ -8071,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));
@@ -8086,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,
@@ -8112,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();
}
@@ -8133,7 +8571,7 @@ CreateNewDecl:
// check the specialization.
if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous))
Invalid = true;
-
+
if (Invalid)
New->setInvalidDecl();
@@ -8142,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
@@ -8155,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())
@@ -8172,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);
@@ -8180,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);
@@ -8193,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;
}
@@ -8256,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();
@@ -8271,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;
}
@@ -8286,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.
@@ -8294,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;
@@ -8306,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();
@@ -8314,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;
@@ -8343,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()
@@ -8363,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
@@ -8388,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,
@@ -8408,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.
@@ -8430,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);
@@ -8481,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
@@ -8519,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.
@@ -8555,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());
@@ -8565,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();
}
}
@@ -8588,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())
@@ -8600,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;
@@ -8624,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,
@@ -8638,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;
}
}
}
@@ -8650,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) {
@@ -8664,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;
@@ -8699,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;
}
@@ -8731,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;
}
@@ -8741,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;
}
@@ -8768,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;
@@ -8843,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.
@@ -8870,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)) {
@@ -8914,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())
@@ -8980,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) {
@@ -9024,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();
@@ -9101,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.
@@ -9118,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())
@@ -9168,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()) {
@@ -9194,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());
@@ -9266,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);
@@ -9284,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
@@ -9291,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);
}
}
@@ -9360,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();
}
}
}
@@ -9483,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)
@@ -9497,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());
}
@@ -9509,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.
@@ -9533,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))
@@ -9651,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.
@@ -9701,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();
@@ -9715,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;
}
}
@@ -9740,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.
@@ -9772,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.
@@ -9783,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,
@@ -9797,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/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp
index 69baf79..5c6ddd2 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp
index a39584a..847f03c 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp
index 62b4a7c..a942d49 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp
index 92af2d9..42221f8 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp
index 170097c..0d0f2f5 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp
index 3300444..31a8115 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp
index 26867c2..26b88a2 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp
index 20098b2..b62d56e 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaFixItUtils.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaFixItUtils.cpp
index 8e8a46d..b78ea7d 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaFixItUtils.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp
index 7ed3fa8..a65b41f 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp
new file mode 100644
index 0000000..6ef8d88
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp
index d5bee1d..966eb90 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp
index 751f553..5ece8f1 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp
index b0dd5e2..284c8de 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp
new file mode 100644
index 0000000..d52c912
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp
index 5351896..97c8eb0 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp
index 8dda34c..ff8c4da 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp
index 93ea89d..2ea1e6f 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 301bf6a..4740145 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 02a05d5..8afe7ac 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp
index e383db9..a40100c 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp
index 2b563a5..c41df82 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp b/contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp
index aa0bc08..8b19be7 100644
--- a/contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h
index bb49eee..fdb861e 100644
--- a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp
index 445e750..67f74f7 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h
index 367f57f..16db8e3 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp
index de19d85..f91b66c 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp
+++ b/contrib/llvm/tools/clang/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");
@@ -2687,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
@@ -2697,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;
@@ -2770,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.
///
@@ -2788,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);
@@ -2876,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
@@ -2892,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
@@ -2906,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);
}
@@ -2919,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);
@@ -2961,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;
@@ -3010,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;
@@ -3038,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 {
@@ -3050,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);
@@ -3092,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");
@@ -3108,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);
}
}
}
@@ -3119,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]);
}
@@ -3295,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();
@@ -3344,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);
@@ -3364,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;
}
@@ -3429,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: {
@@ -3554,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;
@@ -3576,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)
{ }
@@ -3733,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));
@@ -3747,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)
@@ -3793,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);
@@ -3843,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;
@@ -3856,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");
@@ -3878,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;
@@ -3899,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) {
@@ -3930,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);
@@ -3950,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;
@@ -3983,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;
@@ -3995,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) {
@@ -4019,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();
@@ -4028,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]);
@@ -4048,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()) {
@@ -4093,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;
@@ -4144,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;
@@ -4210,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
@@ -4238,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;
@@ -4331,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) {
@@ -4349,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);
@@ -4392,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();
@@ -4424,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 {
@@ -4491,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);
@@ -4552,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(
@@ -4755,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
@@ -4784,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];
@@ -4805,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;
@@ -4825,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));
}
@@ -4842,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] =
@@ -4864,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;
@@ -4877,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) {
@@ -4913,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) {
@@ -4949,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));
@@ -4959,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++];
@@ -4972,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) {
@@ -5031,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) {
@@ -5070,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);
@@ -5091,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);
@@ -5100,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--) {
@@ -5111,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++]);
@@ -5127,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++];
@@ -5135,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:
@@ -5179,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,
@@ -5209,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;
@@ -5258,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;
@@ -5314,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);
@@ -5361,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);
@@ -5399,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()) {
@@ -5410,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),
@@ -5446,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/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp
index 6cc3f0a..5db5f92 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h
index 99e8be5..3a1dfcf 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderInternals.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp
index ab07b85..2eeb090 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp
index a1645d7..a4301b5 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp
+++ b/contrib/llvm/tools/clang/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);
@@ -2995,7 +3390,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
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);
@@ -3014,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);
@@ -3027,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())
@@ -3103,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);
@@ -3125,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:
@@ -3158,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();
@@ -3176,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());
}
@@ -3397,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) {
@@ -3404,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;
@@ -3419,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());
@@ -3776,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);
@@ -3807,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);
@@ -3824,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);
@@ -3842,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)
@@ -3858,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) {
@@ -3866,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.");
@@ -3874,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) {
@@ -3898,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;
}
@@ -3912,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!");
@@ -3923,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) {
@@ -4023,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/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp
index a8243e5..7a4ef63 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp
index 7e2d45c..827caa0 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp b/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp
index a2534db..02aed10 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/GeneratePCH.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Serialization/Module.cpp b/contrib/llvm/tools/clang/lib/Serialization/Module.cpp
index 0a721c4..16b95e2 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/Module.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp b/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp
index c4b1f71..ab364b7 100644
--- a/contrib/llvm/tools/clang/lib/Serialization/ModuleManager.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
index dc524ba..84ea8c7 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
index cd977bf..aa6f97b 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
index 6935c5f..b2ad184 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 6175028..c6efe94 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
index 8296eb9..ab66e98 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 08cff0f..6dd0a8c 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
new file mode 100644
index 0000000..a4fc396
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index a57d031..509bc79 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 1625219..9eb7edf 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
new file mode 100644
index 0000000..befc935
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 4db6ac0..f601431 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index 84a9e6b..2e184fb 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
index c855210..1407638 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index c325bb1..133204a 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
index c076c1e3..6df47b1 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index bf7ba18..dde9071 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
index 469be05..cc7fd37 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
new file mode 100644
index 0000000..843502f
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td
index d53e0b8..96a8d26 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index 3c92381..30d0609 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckers.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
index 289ce8d..230baa7 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CommonBugCategories.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CommonBugCategories.cpp
new file mode 100644
index 0000000..e2a8ea6
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 901af43..510e8cd 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index d9d5694..34053cd 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index eeda734..81a2745 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
index 75b7cc4..2627f0c 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
index 531d87e..a1f2f3b 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
new file mode 100644
index 0000000..135b81d
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
index 5c257e5..c08f163 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/InterCheckerAPI.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/InterCheckerAPI.h
new file mode 100644
index 0000000..e35557f
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp
index fbc57d3..b0bac33 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
index e398fcb..757a4ce 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 2607db8..cb976e0 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 88d492e..cfdb55d 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 5631802..8bce88a 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
index cf5501a..daec418 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
new file mode 100644
index 0000000..08a9da1
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index 7f74a7d..4989ba8 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 5678998..f826573 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index 81f1924..c2d7c09 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
index f426265..7b724d2 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
index 3e4e07b..777e9ea 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
new file mode 100644
index 0000000..f2929c0
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
new file mode 100644
index 0000000..f4655b6
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index 2fb9944..d15c8ba 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
index bbc262f..4718dc7 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
index 202522b..fe4845b 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index 924c7f2..fa5c6a3 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index c02b5b1..2d018ef 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 93e0fe5..b569e41 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index e761bff..6e56593 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
index e8c8d90..7b1f0b1 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 91c4b96..54cf569 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 1d14e9e..3745d4a 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
new file mode 100644
index 0000000..1133682
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
index b860b34..a30f6d5 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index 2aebed9..d57767e 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index 7ae9668..c3c9ed7 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
index bb6831b..0297c4e 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index 5ca4a9f..78f7fa6 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index cec286d..60e665fe 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index 459ee65..5a13ed0 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index b34b97c..38c9cc1 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
new file mode 100644
index 0000000..f7c7c0c
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AggExprVisitor.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AggExprVisitor.cpp
deleted file mode 100644
index 0936d61..0000000
--- a/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index 17ec70d..82ac8bd 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp
index 6c748b6..2d9addd 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
index fbbdb04..a264212 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 1abd8ba..6532486 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Checker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Checker.cpp
index a3bf2c2..07e0aac 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Checker.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
index 5356edc..0a047d9 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
index acacfb0..0bcc343 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
index 13401ac..9791e2ec 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 5252198..eb986af 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp
index e1b982c..b5ea3db 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index 5762a21..0dcbe1f 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index ac9cf0b..d2da9aa 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 68ccc59..93e598a 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index acb0074..a14a491 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 6d377b9..b99bd54 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index e0560fd..c8ad70a 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/FunctionSummary.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/FunctionSummary.cpp
new file mode 100644
index 0000000..c227aac
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 0c4e427..629f1ea 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
index 6f92da8..ed94c79 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp
index 0974fe8..65cdcd9 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index 3a87903..01dd965 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index 5ae95c6..323cede 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
index 73788cc..b9cfa27 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 9337788..98eb958 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 4b76cf1..cc3ea8c3 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index ebf7ae2..9e97f5e 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp
index b5980b9..b94aff4 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index 79d8b8b..a76a2da 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
index d4295d4..e082d9d 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index bd63ecf..d0558f1 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp
index 48a6f4f..11748ae 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SubEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SubEngine.cpp
new file mode 100644
index 0000000..350f4b8
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
index b843ab1..adefb58 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
index 3543f7f..fe912df 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 34a358f..c19ebcb 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
index a59fcad..c06da0d 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp b/contrib/llvm/tools/clang/lib/Tooling/CompilationDatabase.cpp
new file mode 100644
index 0000000..eea1055
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp b/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp
new file mode 100644
index 0000000..fa2374f
--- /dev/null
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/tools/driver/cc1_main.cpp b/contrib/llvm/tools/clang/tools/driver/cc1_main.cpp
index 27f79b7..a211090 100644
--- a/contrib/llvm/tools/clang/tools/driver/cc1_main.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp b/contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp
index 7cc42aa..508d6da 100644
--- a/contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/tools/driver/driver.cpp b/contrib/llvm/tools/clang/tools/driver/driver.cpp
index bd1d2a2..8c05fff 100644
--- a/contrib/llvm/tools/clang/tools/driver/driver.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/utils/TableGen/CMakeLists.txt b/contrib/llvm/tools/clang/utils/TableGen/CMakeLists.txt
deleted file mode 100644
index 75a6167..0000000
--- a/contrib/llvm/tools/clang/utils/TableGen/CMakeLists.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-set(LLVM_REQUIRES_EH 1)
-set(LLVM_REQUIRES_RTTI 1)
-
-add_tablegen(clang-tblgen CLANG
- ClangASTNodesEmitter.cpp
- ClangAttrEmitter.cpp
- ClangDiagnosticsEmitter.cpp
- ClangSACheckersEmitter.cpp
- NeonEmitter.cpp
- OptParserEmitter.cpp
- TableGen.cpp
- )
diff --git a/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp
index 5c236be..7951fc4 100644
--- a/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.h b/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.h
index 5acca56..d119a09 100644
--- a/contrib/llvm/tools/clang/utils/TableGen/ClangAttrEmitter.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
index da2fb70..8a49619 100644
--- a/contrib/llvm/tools/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/utils/TableGen/Makefile b/contrib/llvm/tools/clang/utils/TableGen/Makefile
deleted file mode 100644
index 9790efc..0000000
--- a/contrib/llvm/tools/clang/utils/TableGen/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-##===- utils/TableGen/Makefile -----------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../../../..
-TOOLNAME = clang-tblgen
-USEDLIBS = LLVMTableGen.a LLVMSupport.a
-REQUIRES_EH := 1
-REQUIRES_RTTI := 1
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-include $(LEVEL)/Makefile.common
diff --git a/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.cpp
index 66845cc..e6f2e53 100644
--- a/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.h b/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.h
index 708ad3c..dec7451 100644
--- a/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.h
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp b/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp
index 5c016d3..5ff88db 100644
--- a/contrib/llvm/tools/clang/utils/TableGen/TableGen.cpp
+++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/llc/CMakeLists.txt b/contrib/llvm/tools/llc/CMakeLists.txt
deleted file mode 100644
index 683f298..0000000
--- a/contrib/llvm/tools/llc/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser)
-
-add_llvm_tool(llc
- llc.cpp
- )
diff --git a/contrib/llvm/tools/llc/Makefile b/contrib/llvm/tools/llc/Makefile
deleted file mode 100644
index 7319aad..0000000
--- a/contrib/llvm/tools/llc/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-#===- tools/llc/Makefile -----------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = llc
-
-# Include this here so we can get the configuration of the targets
-# that have been configured for construction. We have to do this
-# early so we can set up LINK_COMPONENTS before including Makefile.rules
-include $(LEVEL)/Makefile.config
-
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) bitreader asmparser
-
-include $(LLVM_SRC_ROOT)/Makefile.rules
-
diff --git a/contrib/llvm/tools/llc/llc.cpp b/contrib/llvm/tools/llc/llc.cpp
index d29bd9b..9e30ac1 100644
--- a/contrib/llvm/tools/llc/llc.cpp
+++ b/contrib/llvm/tools/llc/llc.cpp
@@ -21,7 +21,6 @@
#include "llvm/Support/IRReader.h"
#include "llvm/CodeGen/LinkAllAsmWriterComponents.h"
#include "llvm/CodeGen/LinkAllCodegenComponents.h"
-#include "llvm/Config/config.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
@@ -133,11 +132,147 @@ cl::opt<bool> DisableDotLoc("disable-dot-loc", cl::Hidden,
cl::opt<bool> DisableCFI("disable-cfi", cl::Hidden,
cl::desc("Do not use .cfi_* directives"));
+cl::opt<bool> EnableDwarfDirectory("enable-dwarf-directory", cl::Hidden,
+ cl::desc("Use .file directives with an explicit directory."));
+
static cl::opt<bool>
DisableRedZone("disable-red-zone",
cl::desc("Do not emit code that uses the red zone."),
cl::init(false));
+static cl::opt<bool>
+EnableFPMAD("enable-fp-mad",
+ cl::desc("Enable less precise MAD instructions to be generated"),
+ cl::init(false));
+
+static cl::opt<bool>
+PrintCode("print-machineinstrs",
+ cl::desc("Print generated machine code"),
+ cl::init(false));
+
+static cl::opt<bool>
+DisableFPElim("disable-fp-elim",
+ cl::desc("Disable frame pointer elimination optimization"),
+ cl::init(false));
+
+static cl::opt<bool>
+DisableFPElimNonLeaf("disable-non-leaf-fp-elim",
+ cl::desc("Disable frame pointer elimination optimization for non-leaf funcs"),
+ cl::init(false));
+
+static cl::opt<bool>
+DisableExcessPrecision("disable-excess-fp-precision",
+ cl::desc("Disable optimizations that may increase FP precision"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableUnsafeFPMath("enable-unsafe-fp-math",
+ cl::desc("Enable optimizations that may decrease FP precision"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableNoInfsFPMath("enable-no-infs-fp-math",
+ cl::desc("Enable FP math optimizations that assume no +-Infs"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableNoNaNsFPMath("enable-no-nans-fp-math",
+ cl::desc("Enable FP math optimizations that assume no NaNs"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math",
+ cl::Hidden,
+ cl::desc("Force codegen to assume rounding mode can change dynamically"),
+ cl::init(false));
+
+static cl::opt<bool>
+GenerateSoftFloatCalls("soft-float",
+ cl::desc("Generate software floating point library calls"),
+ cl::init(false));
+
+static cl::opt<llvm::FloatABI::ABIType>
+FloatABIForCalls("float-abi",
+ cl::desc("Choose float ABI type"),
+ cl::init(FloatABI::Default),
+ cl::values(
+ clEnumValN(FloatABI::Default, "default",
+ "Target default float ABI type"),
+ clEnumValN(FloatABI::Soft, "soft",
+ "Soft float ABI (implied by -soft-float)"),
+ clEnumValN(FloatABI::Hard, "hard",
+ "Hard float ABI (uses FP registers)"),
+ clEnumValEnd));
+
+static cl::opt<bool>
+DontPlaceZerosInBSS("nozero-initialized-in-bss",
+ cl::desc("Don't place zero-initialized symbols into bss section"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableJITExceptionHandling("jit-enable-eh",
+ cl::desc("Emit exception handling information"),
+ cl::init(false));
+
+// In debug builds, make this default to true.
+#ifdef NDEBUG
+#define EMIT_DEBUG false
+#else
+#define EMIT_DEBUG true
+#endif
+static cl::opt<bool>
+EmitJitDebugInfo("jit-emit-debug",
+ cl::desc("Emit debug information to debugger"),
+ cl::init(EMIT_DEBUG));
+#undef EMIT_DEBUG
+
+static cl::opt<bool>
+EmitJitDebugInfoToDisk("jit-emit-debug-to-disk",
+ cl::Hidden,
+ cl::desc("Emit debug info objfiles to disk"),
+ cl::init(false));
+
+static cl::opt<bool>
+EnableGuaranteedTailCallOpt("tailcallopt",
+ cl::desc("Turn fastcc calls into tail calls by (potentially) changing ABI."),
+ cl::init(false));
+
+static cl::opt<bool>
+DisableTailCalls("disable-tail-calls",
+ cl::desc("Never emit tail calls"),
+ cl::init(false));
+
+static cl::opt<unsigned>
+OverrideStackAlignment("stack-alignment",
+ cl::desc("Override default stack alignment"),
+ cl::init(0));
+
+static cl::opt<bool>
+EnableRealignStack("realign-stack",
+ cl::desc("Realign stack if needed"),
+ cl::init(true));
+
+static cl::opt<bool>
+DisableSwitchTables(cl::Hidden, "disable-jump-tables",
+ cl::desc("Do not generate jump tables."),
+ cl::init(false));
+
+static cl::opt<std::string>
+TrapFuncName("trap-func", cl::Hidden,
+ cl::desc("Emit a call to trap function rather than a trap instruction"),
+ cl::init(""));
+
+static cl::opt<bool>
+EnablePIE("enable-pie",
+ cl::desc("Assume the creation of a position independent executable."),
+ cl::init(false));
+
+static cl::opt<bool>
+SegmentedStacks("segmented-stacks",
+ cl::desc("Use segmented stacks if possible."),
+ cl::init(false));
+
+
// GetFileNameRoot - Helper function to get the basename of a filename.
static inline std::string
GetFileNameRoot(const std::string &InputFilename) {
@@ -166,7 +301,6 @@ static tool_output_file *GetOutputStream(const char *TargetName,
OutputFilename = GetFileNameRoot(InputFilename);
switch (FileType) {
- default: assert(0 && "Unknown file type");
case TargetMachine::CGFT_AssemblyFile:
if (TargetName[0] == 'c') {
if (TargetName[1] == 0)
@@ -194,7 +328,6 @@ static tool_output_file *GetOutputStream(const char *TargetName,
// Decide if we need "binary" output.
bool Binary = false;
switch (FileType) {
- default: assert(0 && "Unknown file type");
case TargetMachine::CGFT_AssemblyFile:
break;
case TargetMachine::CGFT_ObjectFile:
@@ -247,7 +380,7 @@ int main(int argc, char **argv) {
M.reset(ParseIRFile(InputFilename, Err, Context));
if (M.get() == 0) {
- Err.Print(argv[0], errs());
+ Err.print(argv[0], errs());
return 1;
}
Module &mod = *M.get();
@@ -258,7 +391,7 @@ int main(int argc, char **argv) {
Triple TheTriple(mod.getTargetTriple());
if (TheTriple.getTriple().empty())
- TheTriple.setTriple(sys::getHostTriple());
+ TheTriple.setTriple(sys::getDefaultTargetTriple());
// Allocate target machine. First, check whether the user has explicitly
// specified an architecture to compile for. If so we have to look it up by
@@ -303,10 +436,49 @@ int main(int argc, char **argv) {
FeaturesStr = Features.getString();
}
+ CodeGenOpt::Level OLvl = CodeGenOpt::Default;
+ switch (OptLevel) {
+ default:
+ errs() << argv[0] << ": invalid optimization level.\n";
+ return 1;
+ case ' ': break;
+ case '0': OLvl = CodeGenOpt::None; break;
+ case '1': OLvl = CodeGenOpt::Less; break;
+ case '2': OLvl = CodeGenOpt::Default; break;
+ case '3': OLvl = CodeGenOpt::Aggressive; break;
+ }
+
+ TargetOptions Options;
+ Options.LessPreciseFPMADOption = EnableFPMAD;
+ Options.PrintMachineCode = PrintCode;
+ Options.NoFramePointerElim = DisableFPElim;
+ Options.NoFramePointerElimNonLeaf = DisableFPElimNonLeaf;
+ Options.NoExcessFPPrecision = DisableExcessPrecision;
+ Options.UnsafeFPMath = EnableUnsafeFPMath;
+ Options.NoInfsFPMath = EnableNoInfsFPMath;
+ Options.NoNaNsFPMath = EnableNoNaNsFPMath;
+ Options.HonorSignDependentRoundingFPMathOption =
+ EnableHonorSignDependentRoundingFPMath;
+ Options.UseSoftFloat = GenerateSoftFloatCalls;
+ if (FloatABIForCalls != FloatABI::Default)
+ Options.FloatABIType = FloatABIForCalls;
+ Options.NoZerosInBSS = DontPlaceZerosInBSS;
+ Options.JITExceptionHandling = EnableJITExceptionHandling;
+ Options.JITEmitDebugInfo = EmitJitDebugInfo;
+ Options.JITEmitDebugInfoToDisk = EmitJitDebugInfoToDisk;
+ Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt;
+ Options.DisableTailCalls = DisableTailCalls;
+ Options.StackAlignmentOverride = OverrideStackAlignment;
+ Options.RealignStack = EnableRealignStack;
+ Options.DisableJumpTables = DisableSwitchTables;
+ Options.TrapFuncName = TrapFuncName;
+ Options.PositionIndependentExecutable = EnablePIE;
+ Options.EnableSegmentedStacks = SegmentedStacks;
+
std::auto_ptr<TargetMachine>
target(TheTarget->createTargetMachine(TheTriple.getTriple(),
- MCPU, FeaturesStr,
- RelocModel, CMModel));
+ MCPU, FeaturesStr, Options,
+ RelocModel, CMModel, OLvl));
assert(target.get() && "Could not allocate target machine!");
TargetMachine &Target = *target.get();
@@ -316,6 +488,12 @@ int main(int argc, char **argv) {
if (DisableCFI)
Target.setMCUseCFI(false);
+ if (EnableDwarfDirectory)
+ Target.setMCUseDwarfDirectory(true);
+
+ if (GenerateSoftFloatCalls)
+ FloatABIForCalls = FloatABI::Soft;
+
// Disable .loc support for older OS X versions.
if (TheTriple.isMacOSX() &&
TheTriple.isMacOSXVersionLT(10, 6))
@@ -326,18 +504,6 @@ int main(int argc, char **argv) {
(GetOutputStream(TheTarget->getName(), TheTriple.getOS(), argv[0]));
if (!Out) return 1;
- CodeGenOpt::Level OLvl = CodeGenOpt::Default;
- switch (OptLevel) {
- default:
- errs() << argv[0] << ": invalid optimization level.\n";
- return 1;
- case ' ': break;
- case '0': OLvl = CodeGenOpt::None; break;
- case '1': OLvl = CodeGenOpt::Less; break;
- case '2': OLvl = CodeGenOpt::Default; break;
- case '3': OLvl = CodeGenOpt::Aggressive; break;
- }
-
// Build up all of the passes that we want to do to the module.
PassManager PM;
@@ -362,7 +528,7 @@ int main(int argc, char **argv) {
formatted_raw_ostream FOS(Out->os());
// Ask the target to add backend passes as necessary.
- if (Target.addPassesToEmitFile(PM, FOS, FileType, OLvl, NoVerify)) {
+ if (Target.addPassesToEmitFile(PM, FOS, FileType, NoVerify)) {
errs() << argv[0] << ": target does not support generation of this"
<< " file type!\n";
return 1;
diff --git a/contrib/llvm/tools/lli/CMakeLists.txt b/contrib/llvm/tools/lli/CMakeLists.txt
deleted file mode 100644
index 9378ef2..0000000
--- a/contrib/llvm/tools/lli/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser selectiondag)
-
-add_llvm_tool(lli
- lli.cpp
- )
diff --git a/contrib/llvm/tools/lli/Makefile b/contrib/llvm/tools/lli/Makefile
deleted file mode 100644
index 80aa82b..0000000
--- a/contrib/llvm/tools/lli/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-##===- tools/lli/Makefile ------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL := ../..
-TOOLNAME := lli
-LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser selectiondag
-
-# Enable JIT support
-include $(LEVEL)/Makefile.common
diff --git a/contrib/llvm/tools/lli/lli.cpp b/contrib/llvm/tools/lli/lli.cpp
index 50c7a49..efcc1f5 100644
--- a/contrib/llvm/tools/lli/lli.cpp
+++ b/contrib/llvm/tools/lli/lli.cpp
@@ -23,6 +23,7 @@
#include "llvm/ExecutionEngine/Interpreter.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
+#include "llvm/ExecutionEngine/JITMemoryManager.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/IRReader.h"
@@ -94,12 +95,12 @@ namespace {
"of the executable"),
cl::value_desc("function"),
cl::init("main"));
-
+
cl::opt<std::string>
FakeArgv0("fake-argv0",
cl::desc("Override the 'argv[0]' value passed into the executing"
" program"), cl::value_desc("executable"));
-
+
cl::opt<bool>
DisableCoreFiles("disable-core-files", cl::Hidden,
cl::desc("Disable emission of core files if possible"));
@@ -158,7 +159,7 @@ static void do_shutdown() {
int main(int argc, char **argv, char * const *envp) {
sys::PrintStackTraceOnErrorSignal();
PrettyStackTraceProgram X(argc, argv);
-
+
LLVMContext &Context = getGlobalContext();
atexit(do_shutdown); // Call llvm_shutdown() on exit.
@@ -173,12 +174,12 @@ int main(int argc, char **argv, char * const *envp) {
// If the user doesn't want core files, disable them.
if (DisableCoreFiles)
sys::Process::PreventCoreFiles();
-
+
// Load the bitcode...
SMDiagnostic Err;
Module *Mod = ParseIRFile(InputFile, Err, Context);
if (!Mod) {
- Err.Print(argv[0], errs());
+ Err.print(argv[0], errs());
return 1;
}
@@ -199,6 +200,8 @@ int main(int argc, char **argv, char * const *envp) {
builder.setRelocationModel(RelocModel);
builder.setCodeModel(CMModel);
builder.setErrorStr(&ErrorMsg);
+ builder.setJITMemoryManager(ForceInterpreter ? 0 :
+ JITMemoryManager::CreateDefaultMemManager());
builder.setEngineKind(ForceInterpreter
? EngineKind::Interpreter
: EngineKind::JIT);
@@ -207,9 +210,11 @@ int main(int argc, char **argv, char * const *envp) {
if (!TargetTriple.empty())
Mod->setTargetTriple(Triple::normalize(TargetTriple));
- // Enable MCJIT, if desired.
- if (UseMCJIT)
+ // Enable MCJIT if desired.
+ if (UseMCJIT && !ForceInterpreter) {
builder.setUseMCJIT(true);
+ builder.setJITMemoryManager(JITMemoryManager::CreateDefaultMemManager());
+ }
CodeGenOpt::Level OLvl = CodeGenOpt::Default;
switch (OptLevel) {
@@ -233,7 +238,12 @@ int main(int argc, char **argv, char * const *envp) {
exit(1);
}
- EE->RegisterJITEventListener(createOProfileJITEventListener());
+ // The following functions have no effect if their respective profiling
+ // support wasn't enabled in the build configuration.
+ EE->RegisterJITEventListener(
+ JITEventListener::createOProfileJITEventListener());
+ EE->RegisterJITEventListener(
+ JITEventListener::createIntelJITEventListener());
EE->DisableLazyCompilation(NoLazyCompilation);
@@ -262,15 +272,15 @@ int main(int argc, char **argv, char * const *envp) {
return -1;
}
- // If the program doesn't explicitly call exit, we will need the Exit
- // function later on to make an explicit call, so get the function now.
+ // If the program doesn't explicitly call exit, we will need the Exit
+ // function later on to make an explicit call, so get the function now.
Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context),
Type::getInt32Ty(Context),
NULL);
-
+
// Reset errno to zero on entry to main.
errno = 0;
-
+
// Run static constructors.
EE->runStaticConstructorsDestructors(false);
@@ -287,8 +297,8 @@ int main(int argc, char **argv, char * const *envp) {
// Run static destructors.
EE->runStaticConstructorsDestructors(true);
-
- // If the program didn't call exit explicitly, we should call it now.
+
+ // If the program didn't call exit explicitly, we should call it now.
// This ensures that any atexit handlers get called correctly.
if (Function *ExitF = dyn_cast<Function>(Exit)) {
std::vector<GenericValue> Args;
diff --git a/contrib/llvm/tools/llvm-ar/CMakeLists.txt b/contrib/llvm/tools/llvm-ar/CMakeLists.txt
deleted file mode 100644
index c8b0b72..0000000
--- a/contrib/llvm/tools/llvm-ar/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-set(LLVM_LINK_COMPONENTS archive)
-set(LLVM_REQUIRES_EH 1)
-
-add_llvm_tool(llvm-ar
- llvm-ar.cpp
- )
-
-# TODO: Support check-local.
diff --git a/contrib/llvm/tools/llvm-ar/Makefile b/contrib/llvm/tools/llvm-ar/Makefile
deleted file mode 100644
index e4fe4e8..0000000
--- a/contrib/llvm/tools/llvm-ar/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
-##===- tools/llvm-ar/Makefile ------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-LEVEL = ../..
-
-TOOLNAME = llvm-ar
-LINK_COMPONENTS = archive
-REQUIRES_EH := 1
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-include $(LEVEL)/Makefile.common
-
-check-local::
- $(Echo) Checking llvm-ar
- $(Verb) $(ToolDir)/llvm-ar zRrS nada.a .
- $(Verb) $(ToolDir)/llvm-ar tv nada.a | \
- grep Debug/llvm-ar.d >/dev/null 2>&1
- $(Verb) $(RM) -f nada.a
diff --git a/contrib/llvm/tools/llvm-as/CMakeLists.txt b/contrib/llvm/tools/llvm-as/CMakeLists.txt
deleted file mode 100644
index eef4a13..0000000
--- a/contrib/llvm/tools/llvm-as/CMakeLists.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-set(LLVM_LINK_COMPONENTS asmparser bitwriter)
-set(LLVM_REQUIRES_EH 1)
-
-add_llvm_tool(llvm-as
- llvm-as.cpp
- )
diff --git a/contrib/llvm/tools/llvm-as/Makefile b/contrib/llvm/tools/llvm-as/Makefile
deleted file mode 100644
index e1e5853..0000000
--- a/contrib/llvm/tools/llvm-as/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-##===- tools/llvm-as/Makefile ------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = llvm-as
-LINK_COMPONENTS := asmparser bitwriter
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-include $(LEVEL)/Makefile.common
diff --git a/contrib/llvm/tools/llvm-as/llvm-as.cpp b/contrib/llvm/tools/llvm-as/llvm-as.cpp
index c1661cd..1def9a4 100644
--- a/contrib/llvm/tools/llvm-as/llvm-as.cpp
+++ b/contrib/llvm/tools/llvm-as/llvm-as.cpp
@@ -96,7 +96,7 @@ int main(int argc, char **argv) {
SMDiagnostic Err;
std::auto_ptr<Module> M(ParseAssemblyFile(InputFilename, Err, Context));
if (M.get() == 0) {
- Err.Print(argv[0], errs());
+ Err.print(argv[0], errs());
return 1;
}
diff --git a/contrib/llvm/tools/llvm-bcanalyzer/CMakeLists.txt b/contrib/llvm/tools/llvm-bcanalyzer/CMakeLists.txt
deleted file mode 100644
index 732bc32..0000000
--- a/contrib/llvm/tools/llvm-bcanalyzer/CMakeLists.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-set(LLVM_LINK_COMPONENTS bitreader)
-set(LLVM_REQUIRES_EH 1)
-
-add_llvm_tool(llvm-bcanalyzer
- llvm-bcanalyzer.cpp
- )
diff --git a/contrib/llvm/tools/llvm-bcanalyzer/Makefile b/contrib/llvm/tools/llvm-bcanalyzer/Makefile
deleted file mode 100644
index 488387d..0000000
--- a/contrib/llvm/tools/llvm-bcanalyzer/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-##===- tools/llvm-bcanalyzer/Makefile ----------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-LEVEL = ../..
-
-TOOLNAME = llvm-bcanalyzer
-LINK_COMPONENTS := bitreader
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-include $(LEVEL)/Makefile.common
diff --git a/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
index 4ada64a..d630087 100644
--- a/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
+++ b/contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
@@ -102,14 +102,13 @@ static const char *GetBlockName(unsigned BlockID,
default: return 0;
case bitc::MODULE_BLOCK_ID: return "MODULE_BLOCK";
case bitc::PARAMATTR_BLOCK_ID: return "PARAMATTR_BLOCK";
- case bitc::TYPE_BLOCK_ID_OLD: return "TYPE_BLOCK_ID_OLD";
case bitc::TYPE_BLOCK_ID_NEW: return "TYPE_BLOCK_ID";
case bitc::CONSTANTS_BLOCK_ID: return "CONSTANTS_BLOCK";
case bitc::FUNCTION_BLOCK_ID: return "FUNCTION_BLOCK";
- case bitc::TYPE_SYMTAB_BLOCK_ID_OLD: return "TYPE_SYMTAB_OLD";
case bitc::VALUE_SYMTAB_BLOCK_ID: return "VALUE_SYMTAB";
case bitc::METADATA_BLOCK_ID: return "METADATA_BLOCK";
case bitc::METADATA_ATTACHMENT_ID: return "METADATA_ATTACHMENT_BLOCK";
+ case bitc::USELIST_BLOCK_ID: return "USELIST_BLOCK_ID";
}
}
@@ -163,7 +162,6 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
default: return 0;
case bitc::PARAMATTR_CODE_ENTRY: return "ENTRY";
}
- case bitc::TYPE_BLOCK_ID_OLD:
case bitc::TYPE_BLOCK_ID_NEW:
switch (CodeID) {
default: return 0;
@@ -175,8 +173,6 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
case bitc::TYPE_CODE_OPAQUE: return "OPAQUE";
case bitc::TYPE_CODE_INTEGER: return "INTEGER";
case bitc::TYPE_CODE_POINTER: return "POINTER";
- case bitc::TYPE_CODE_FUNCTION: return "FUNCTION";
- case bitc::TYPE_CODE_STRUCT_OLD: return "STRUCT_OLD";
case bitc::TYPE_CODE_ARRAY: return "ARRAY";
case bitc::TYPE_CODE_VECTOR: return "VECTOR";
case bitc::TYPE_CODE_X86_FP80: return "X86_FP80";
@@ -186,6 +182,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
case bitc::TYPE_CODE_STRUCT_ANON: return "STRUCT_ANON";
case bitc::TYPE_CODE_STRUCT_NAME: return "STRUCT_NAME";
case bitc::TYPE_CODE_STRUCT_NAMED: return "STRUCT_NAMED";
+ case bitc::TYPE_CODE_FUNCTION: return "FUNCTION";
}
case bitc::CONSTANTS_BLOCK_ID:
@@ -211,6 +208,8 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
case bitc::CST_CODE_CE_CMP: return "CE_CMP";
case bitc::CST_CODE_INLINEASM: return "INLINEASM";
case bitc::CST_CODE_CE_SHUFVEC_EX: return "CE_SHUFVEC_EX";
+ case bitc::CST_CODE_BLOCKADDRESS: return "CST_CODE_BLOCKADDRESS";
+ case bitc::CST_CODE_DATA: return "DATA";
}
case bitc::FUNCTION_BLOCK_ID:
switch (CodeID) {
@@ -231,7 +230,6 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
case bitc::FUNC_CODE_INST_BR: return "INST_BR";
case bitc::FUNC_CODE_INST_SWITCH: return "INST_SWITCH";
case bitc::FUNC_CODE_INST_INVOKE: return "INST_INVOKE";
- case bitc::FUNC_CODE_INST_UNWIND: return "INST_UNWIND";
case bitc::FUNC_CODE_INST_UNREACHABLE: return "INST_UNREACHABLE";
case bitc::FUNC_CODE_INST_PHI: return "INST_PHI";
@@ -247,11 +245,6 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
case bitc::FUNC_CODE_INST_CALL: return "INST_CALL";
case bitc::FUNC_CODE_DEBUG_LOC: return "DEBUG_LOC";
}
- case bitc::TYPE_SYMTAB_BLOCK_ID_OLD:
- switch (CodeID) {
- default: return 0;
- case bitc::TST_CODE_ENTRY: return "ENTRY";
- }
case bitc::VALUE_SYMTAB_BLOCK_ID:
switch (CodeID) {
default: return 0;
@@ -273,6 +266,11 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
case bitc::METADATA_FN_NODE: return "METADATA_FN_NODE";
case bitc::METADATA_NAMED_NODE: return "METADATA_NAMED_NODE";
}
+ case bitc::USELIST_BLOCK_ID:
+ switch(CodeID) {
+ default:return 0;
+ case bitc::USELIST_CODE_ENTRY: return "USELIST_CODE_ENTRY";
+ }
}
}
@@ -333,7 +331,7 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) {
// BLOCKINFO is a special part of the stream.
if (BlockID == bitc::BLOCKINFO_BLOCK_ID) {
- if (Dump) errs() << Indent << "<BLOCKINFO_BLOCK/>\n";
+ if (Dump) outs() << Indent << "<BLOCKINFO_BLOCK/>\n";
if (Stream.ReadBlockInfoBlock())
return Error("Malformed BlockInfoBlock");
uint64_t BlockBitEnd = Stream.GetCurrentBitNo();
@@ -347,16 +345,16 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) {
const char *BlockName = 0;
if (Dump) {
- errs() << Indent << "<";
+ outs() << Indent << "<";
if ((BlockName = GetBlockName(BlockID, *Stream.getBitStreamReader())))
- errs() << BlockName;
+ outs() << BlockName;
else
- errs() << "UnknownBlock" << BlockID;
+ outs() << "UnknownBlock" << BlockID;
if (NonSymbolic && BlockName)
- errs() << " BlockID=" << BlockID;
+ outs() << " BlockID=" << BlockID;
- errs() << " NumWords=" << NumWords
+ outs() << " NumWords=" << NumWords
<< " BlockCodeSize=" << Stream.GetAbbrevIDWidth() << ">\n";
}
@@ -378,11 +376,11 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) {
uint64_t BlockBitEnd = Stream.GetCurrentBitNo();
BlockStats.NumBits += BlockBitEnd-BlockBitStart;
if (Dump) {
- errs() << Indent << "</";
+ outs() << Indent << "</";
if (BlockName)
- errs() << BlockName << ">\n";
+ outs() << BlockName << ">\n";
else
- errs() << "UnknownBlock" << BlockID << ">\n";
+ outs() << "UnknownBlock" << BlockID << ">\n";
}
return false;
}
@@ -424,25 +422,25 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) {
BlockStats.CodeFreq[Code].NumAbbrev++;
if (Dump) {
- errs() << Indent << " <";
+ outs() << Indent << " <";
if (const char *CodeName =
GetCodeName(Code, BlockID, *Stream.getBitStreamReader()))
- errs() << CodeName;
+ outs() << CodeName;
else
- errs() << "UnknownCode" << Code;
+ outs() << "UnknownCode" << Code;
if (NonSymbolic &&
GetCodeName(Code, BlockID, *Stream.getBitStreamReader()))
- errs() << " codeid=" << Code;
+ outs() << " codeid=" << Code;
if (AbbrevID != bitc::UNABBREV_RECORD)
- errs() << " abbrevid=" << AbbrevID;
+ outs() << " abbrevid=" << AbbrevID;
for (unsigned i = 0, e = Record.size(); i != e; ++i)
- errs() << " op" << i << "=" << (int64_t)Record[i];
+ outs() << " op" << i << "=" << (int64_t)Record[i];
- errs() << "/>";
+ outs() << "/>";
if (BlobStart) {
- errs() << " blob data = ";
+ outs() << " blob data = ";
bool BlobIsPrintable = true;
for (unsigned i = 0; i != BlobLen; ++i)
if (!isprint(BlobStart[i])) {
@@ -451,12 +449,12 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) {
}
if (BlobIsPrintable)
- errs() << "'" << std::string(BlobStart, BlobStart+BlobLen) <<"'";
+ outs() << "'" << std::string(BlobStart, BlobStart+BlobLen) <<"'";
else
- errs() << "unprintable, " << BlobLen << " bytes.";
+ outs() << "unprintable, " << BlobLen << " bytes.";
}
- errs() << "\n";
+ outs() << "\n";
}
break;
@@ -485,13 +483,13 @@ static int AnalyzeBitcode() {
if (MemBuf->getBufferSize() & 3)
return Error("Bitcode stream should be a multiple of 4 bytes in length");
- unsigned char *BufPtr = (unsigned char *)MemBuf->getBufferStart();
- unsigned char *EndBufPtr = BufPtr+MemBuf->getBufferSize();
+ const unsigned char *BufPtr = (unsigned char *)MemBuf->getBufferStart();
+ const unsigned char *EndBufPtr = BufPtr+MemBuf->getBufferSize();
// If we have a wrapper header, parse it and ignore the non-bc file contents.
// The magic number is 0x0B17C0DE stored in little endian.
if (isBitcodeWrapper(BufPtr, EndBufPtr))
- if (SkipBitcodeWrapperHeader(BufPtr, EndBufPtr))
+ if (SkipBitcodeWrapperHeader(BufPtr, EndBufPtr, true))
return Error("Invalid bitcode wrapper header");
BitstreamReader StreamFile(BufPtr, EndBufPtr);
@@ -527,59 +525,58 @@ static int AnalyzeBitcode() {
++NumTopBlocks;
}
- if (Dump) errs() << "\n\n";
+ if (Dump) outs() << "\n\n";
uint64_t BufferSizeBits = (EndBufPtr-BufPtr)*CHAR_BIT;
// Print a summary of the read file.
- errs() << "Summary of " << InputFilename << ":\n";
- errs() << " Total size: ";
+ outs() << "Summary of " << InputFilename << ":\n";
+ outs() << " Total size: ";
PrintSize(BufferSizeBits);
- errs() << "\n";
- errs() << " Stream type: ";
+ outs() << "\n";
+ outs() << " Stream type: ";
switch (CurStreamType) {
- default: assert(0 && "Unknown bitstream type");
- case UnknownBitstream: errs() << "unknown\n"; break;
- case LLVMIRBitstream: errs() << "LLVM IR\n"; break;
+ case UnknownBitstream: outs() << "unknown\n"; break;
+ case LLVMIRBitstream: outs() << "LLVM IR\n"; break;
}
- errs() << " # Toplevel Blocks: " << NumTopBlocks << "\n";
- errs() << "\n";
+ outs() << " # Toplevel Blocks: " << NumTopBlocks << "\n";
+ outs() << "\n";
// Emit per-block stats.
- errs() << "Per-block Summary:\n";
+ outs() << "Per-block Summary:\n";
for (std::map<unsigned, PerBlockIDStats>::iterator I = BlockIDStats.begin(),
E = BlockIDStats.end(); I != E; ++I) {
- errs() << " Block ID #" << I->first;
+ outs() << " Block ID #" << I->first;
if (const char *BlockName = GetBlockName(I->first, StreamFile))
- errs() << " (" << BlockName << ")";
- errs() << ":\n";
+ outs() << " (" << BlockName << ")";
+ outs() << ":\n";
const PerBlockIDStats &Stats = I->second;
- errs() << " Num Instances: " << Stats.NumInstances << "\n";
- errs() << " Total Size: ";
+ outs() << " Num Instances: " << Stats.NumInstances << "\n";
+ outs() << " Total Size: ";
PrintSize(Stats.NumBits);
- errs() << "\n";
+ outs() << "\n";
double pct = (Stats.NumBits * 100.0) / BufferSizeBits;
errs() << " Percent of file: " << format("%2.4f%%", pct) << "\n";
if (Stats.NumInstances > 1) {
- errs() << " Average Size: ";
+ outs() << " Average Size: ";
PrintSize(Stats.NumBits/(double)Stats.NumInstances);
- errs() << "\n";
- errs() << " Tot/Avg SubBlocks: " << Stats.NumSubBlocks << "/"
+ outs() << "\n";
+ outs() << " Tot/Avg SubBlocks: " << Stats.NumSubBlocks << "/"
<< Stats.NumSubBlocks/(double)Stats.NumInstances << "\n";
- errs() << " Tot/Avg Abbrevs: " << Stats.NumAbbrevs << "/"
+ outs() << " Tot/Avg Abbrevs: " << Stats.NumAbbrevs << "/"
<< Stats.NumAbbrevs/(double)Stats.NumInstances << "\n";
- errs() << " Tot/Avg Records: " << Stats.NumRecords << "/"
+ outs() << " Tot/Avg Records: " << Stats.NumRecords << "/"
<< Stats.NumRecords/(double)Stats.NumInstances << "\n";
} else {
- errs() << " Num SubBlocks: " << Stats.NumSubBlocks << "\n";
- errs() << " Num Abbrevs: " << Stats.NumAbbrevs << "\n";
- errs() << " Num Records: " << Stats.NumRecords << "\n";
+ outs() << " Num SubBlocks: " << Stats.NumSubBlocks << "\n";
+ outs() << " Num Abbrevs: " << Stats.NumAbbrevs << "\n";
+ outs() << " Num Records: " << Stats.NumRecords << "\n";
}
if (Stats.NumRecords) {
double pct = (Stats.NumAbbreviatedRecords * 100.0) / Stats.NumRecords;
- errs() << " Percent Abbrevs: " << format("%2.4f%%", pct) << "\n";
+ outs() << " Percent Abbrevs: " << format("%2.4f%%", pct) << "\n";
}
- errs() << "\n";
+ outs() << "\n";
// Print a histogram of the codes we see.
if (!NoHistogram && !Stats.CodeFreq.empty()) {
@@ -590,7 +587,7 @@ static int AnalyzeBitcode() {
std::stable_sort(FreqPairs.begin(), FreqPairs.end());
std::reverse(FreqPairs.begin(), FreqPairs.end());
- errs() << "\tRecord Histogram:\n";
+ outs() << "\tRecord Histogram:\n";
fprintf(stderr, "\t\t Count # Bits %% Abv Record Kind\n");
for (unsigned i = 0, e = FreqPairs.size(); i != e; ++i) {
const PerRecordStats &RecStats = Stats.CodeFreq[FreqPairs[i].second];
@@ -610,7 +607,7 @@ static int AnalyzeBitcode() {
else
fprintf(stderr, "UnknownCode%d\n", FreqPairs[i].second);
}
- errs() << "\n";
+ outs() << "\n";
}
}
diff --git a/contrib/llvm/tools/llvm-diff/CMakeLists.txt b/contrib/llvm/tools/llvm-diff/CMakeLists.txt
deleted file mode 100644
index c59d69e..0000000
--- a/contrib/llvm/tools/llvm-diff/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-set(LLVM_LINK_COMPONENTS support asmparser bitreader)
-
-add_llvm_tool(llvm-diff
- llvm-diff.cpp
- DiffConsumer.cpp
- DiffLog.cpp
- DifferenceEngine.cpp
- )
diff --git a/contrib/llvm/tools/llvm-diff/DiffConsumer.cpp b/contrib/llvm/tools/llvm-diff/DiffConsumer.cpp
index c23e8fb..0528039 100644
--- a/contrib/llvm/tools/llvm-diff/DiffConsumer.cpp
+++ b/contrib/llvm/tools/llvm-diff/DiffConsumer.cpp
@@ -44,6 +44,8 @@ static void ComputeNumbering(Function *F, DenseMap<Value*,unsigned> &Numbering){
}
+void Consumer::anchor() { }
+
void DiffConsumer::printValue(Value *V, bool isL) {
if (V->hasName()) {
out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName();
@@ -64,6 +66,10 @@ void DiffConsumer::printValue(Value *V, bool isL) {
}
return;
}
+ if (isa<Constant>(V)) {
+ out << *V;
+ return;
+ }
unsigned N = contexts.size();
while (N > 0) {
diff --git a/contrib/llvm/tools/llvm-diff/DiffConsumer.h b/contrib/llvm/tools/llvm-diff/DiffConsumer.h
index b95d427..2060fe1 100644
--- a/contrib/llvm/tools/llvm-diff/DiffConsumer.h
+++ b/contrib/llvm/tools/llvm-diff/DiffConsumer.h
@@ -29,6 +29,7 @@ namespace llvm {
/// The interface for consumers of difference data.
class Consumer {
+ virtual void anchor();
public:
/// Record that a local context has been entered. Left and
/// Right are IR "containers" of some sort which are being
diff --git a/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp b/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp
index b240d8c..a5a99f5 100644
--- a/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp
+++ b/contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp
@@ -319,15 +319,19 @@ class FunctionDifferenceEngine {
bool Difference = false;
DenseMap<ConstantInt*,BasicBlock*> LCases;
- for (unsigned I = 1, E = LI->getNumCases(); I != E; ++I)
- LCases[LI->getCaseValue(I)] = LI->getSuccessor(I);
- for (unsigned I = 1, E = RI->getNumCases(); I != E; ++I) {
- ConstantInt *CaseValue = RI->getCaseValue(I);
+
+ for (SwitchInst::CaseIt I = LI->case_begin(), E = LI->case_end();
+ I != E; ++I)
+ LCases[I.getCaseValue()] = I.getCaseSuccessor();
+
+ for (SwitchInst::CaseIt I = RI->case_begin(), E = RI->case_end();
+ I != E; ++I) {
+ ConstantInt *CaseValue = I.getCaseValue();
BasicBlock *LCase = LCases[CaseValue];
if (LCase) {
- if (TryUnify) tryUnify(LCase, RI->getSuccessor(I));
+ if (TryUnify) tryUnify(LCase, I.getCaseSuccessor());
LCases.erase(CaseValue);
- } else if (!Difference) {
+ } else if (Complain || !Difference) {
if (Complain)
Engine.logf("right switch has extra case %r") << CaseValue;
Difference = true;
@@ -628,6 +632,8 @@ void FunctionDifferenceEngine::runBlockDiff(BasicBlock::iterator LStart,
}
+void DifferenceEngine::Oracle::anchor() { }
+
void DifferenceEngine::diff(Function *L, Function *R) {
Context C(*this, L, R);
diff --git a/contrib/llvm/tools/llvm-diff/DifferenceEngine.h b/contrib/llvm/tools/llvm-diff/DifferenceEngine.h
index 5b4f80b..7ea79e4 100644
--- a/contrib/llvm/tools/llvm-diff/DifferenceEngine.h
+++ b/contrib/llvm/tools/llvm-diff/DifferenceEngine.h
@@ -50,7 +50,9 @@ namespace llvm {
/// An oracle for answering whether two values are equivalent as
/// operands.
- struct Oracle {
+ class Oracle {
+ virtual void anchor();
+ public:
virtual bool operator()(Value *L, Value *R) = 0;
protected:
diff --git a/contrib/llvm/tools/llvm-diff/Makefile b/contrib/llvm/tools/llvm-diff/Makefile
deleted file mode 100644
index 58e49fa..0000000
--- a/contrib/llvm/tools/llvm-diff/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-##===- tools/llvm-diff/Makefile ----------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = llvm-diff
-LINK_COMPONENTS := asmparser bitreader
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-include $(LEVEL)/Makefile.common
diff --git a/contrib/llvm/tools/llvm-diff/llvm-diff.cpp b/contrib/llvm/tools/llvm-diff/llvm-diff.cpp
index 76853f1..774169b 100644
--- a/contrib/llvm/tools/llvm-diff/llvm-diff.cpp
+++ b/contrib/llvm/tools/llvm-diff/llvm-diff.cpp
@@ -38,7 +38,7 @@ static Module *ReadModule(LLVMContext &Context, StringRef Name) {
SMDiagnostic Diag;
Module *M = ParseIRFile(Name, Diag, Context);
if (!M)
- Diag.Print("llvmdiff", errs());
+ Diag.print("llvm-diff", errs());
return M;
}
diff --git a/contrib/llvm/tools/llvm-dis/CMakeLists.txt b/contrib/llvm/tools/llvm-dis/CMakeLists.txt
deleted file mode 100644
index 3125f8a..0000000
--- a/contrib/llvm/tools/llvm-dis/CMakeLists.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-set(LLVM_LINK_COMPONENTS bitreader analysis)
-set(LLVM_REQUIRES_EH 1)
-
-add_llvm_tool(llvm-dis
- llvm-dis.cpp
- )
diff --git a/contrib/llvm/tools/llvm-dis/Makefile b/contrib/llvm/tools/llvm-dis/Makefile
deleted file mode 100644
index be71100..0000000
--- a/contrib/llvm/tools/llvm-dis/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-##===- tools/llvm-dis/Makefile ------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-LEVEL = ../..
-
-TOOLNAME = llvm-dis
-LINK_COMPONENTS := bitreader analysis
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-include $(LEVEL)/Makefile.common
diff --git a/contrib/llvm/tools/llvm-dis/llvm-dis.cpp b/contrib/llvm/tools/llvm-dis/llvm-dis.cpp
index 9020a52..6450ea6 100644
--- a/contrib/llvm/tools/llvm-dis/llvm-dis.cpp
+++ b/contrib/llvm/tools/llvm-dis/llvm-dis.cpp
@@ -24,6 +24,7 @@
#include "llvm/Analysis/DebugInfo.h"
#include "llvm/Assembly/AssemblyAnnotationWriter.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/DataStream.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -126,12 +127,19 @@ int main(int argc, char **argv) {
std::string ErrorMessage;
std::auto_ptr<Module> M;
- {
- OwningPtr<MemoryBuffer> BufferPtr;
- if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, BufferPtr))
- ErrorMessage = ec.message();
+ // Use the bitcode streaming interface
+ DataStreamer *streamer = getDataFileStreamer(InputFilename, &ErrorMessage);
+ if (streamer) {
+ std::string DisplayFilename;
+ if (InputFilename == "-")
+ DisplayFilename = "<stdin>";
else
- M.reset(ParseBitcodeFile(BufferPtr.get(), Context, &ErrorMessage));
+ DisplayFilename = InputFilename;
+ M.reset(getStreamedBitcodeModule(DisplayFilename, streamer, Context,
+ &ErrorMessage));
+ if(M.get() != 0 && M->MaterializeAllPermanently(&ErrorMessage)) {
+ M.reset();
+ }
}
if (M.get() == 0) {
@@ -183,4 +191,3 @@ int main(int argc, char **argv) {
return 0;
}
-
diff --git a/contrib/llvm/tools/llvm-extract/CMakeLists.txt b/contrib/llvm/tools/llvm-extract/CMakeLists.txt
deleted file mode 100644
index a4e3266..0000000
--- a/contrib/llvm/tools/llvm-extract/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-set(LLVM_LINK_COMPONENTS asmparser ipo bitreader bitwriter)
-
-add_llvm_tool(llvm-extract
- llvm-extract.cpp
- )
diff --git a/contrib/llvm/tools/llvm-extract/Makefile b/contrib/llvm/tools/llvm-extract/Makefile
deleted file mode 100644
index 5672aa3..0000000
--- a/contrib/llvm/tools/llvm-extract/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-##===- tools/llvm-extract/Makefile -------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-
-TOOLNAME = llvm-extract
-LINK_COMPONENTS := ipo bitreader bitwriter asmparser
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-include $(LEVEL)/Makefile.common
diff --git a/contrib/llvm/tools/llvm-extract/llvm-extract.cpp b/contrib/llvm/tools/llvm-extract/llvm-extract.cpp
index f6227ee..2ed11c5 100644
--- a/contrib/llvm/tools/llvm-extract/llvm-extract.cpp
+++ b/contrib/llvm/tools/llvm-extract/llvm-extract.cpp
@@ -90,7 +90,7 @@ int main(int argc, char **argv) {
M.reset(getLazyIRFileModule(InputFilename, Err, Context));
if (M.get() == 0) {
- Err.Print(argv[0], errs());
+ Err.print(argv[0], errs());
return 1;
}
@@ -99,7 +99,7 @@ int main(int argc, char **argv) {
// Figure out which globals we should extract.
for (size_t i = 0, e = ExtractGlobals.size(); i != e; ++i) {
- GlobalValue *GV = M.get()->getNamedGlobal(ExtractGlobals[i]);
+ GlobalValue *GV = M->getNamedGlobal(ExtractGlobals[i]);
if (!GV) {
errs() << argv[0] << ": program doesn't contain global named '"
<< ExtractGlobals[i] << "'!\n";
@@ -117,8 +117,8 @@ int main(int argc, char **argv) {
"invalid regex: " << Error;
}
bool match = false;
- for (Module::global_iterator GV = M.get()->global_begin(),
- E = M.get()->global_end(); GV != E; GV++) {
+ for (Module::global_iterator GV = M->global_begin(),
+ E = M->global_end(); GV != E; GV++) {
if (RegEx.match(GV->getName())) {
GVs.insert(&*GV);
match = true;
@@ -133,7 +133,7 @@ int main(int argc, char **argv) {
// Figure out which functions we should extract.
for (size_t i = 0, e = ExtractFuncs.size(); i != e; ++i) {
- GlobalValue *GV = M.get()->getFunction(ExtractFuncs[i]);
+ GlobalValue *GV = M->getFunction(ExtractFuncs[i]);
if (!GV) {
errs() << argv[0] << ": program doesn't contain function named '"
<< ExtractFuncs[i] << "'!\n";
@@ -151,7 +151,7 @@ int main(int argc, char **argv) {
"invalid regex: " << Error;
}
bool match = false;
- for (Module::iterator F = M.get()->begin(), E = M.get()->end(); F != E;
+ for (Module::iterator F = M->begin(), E = M->end(); F != E;
F++) {
if (RegEx.match(F->getName())) {
GVs.insert(&*F);
diff --git a/contrib/llvm/tools/llvm-ld/CMakeLists.txt b/contrib/llvm/tools/llvm-ld/CMakeLists.txt
deleted file mode 100644
index 370bcb4..0000000
--- a/contrib/llvm/tools/llvm-ld/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-set(LLVM_LINK_COMPONENTS ipo scalaropts linker archive bitwriter)
-
-add_llvm_tool(llvm-ld
- Optimize.cpp
- llvm-ld.cpp
- )
-
-add_dependencies(llvm-ld llvm-stub)
diff --git a/contrib/llvm/tools/llvm-ld/Makefile b/contrib/llvm/tools/llvm-ld/Makefile
deleted file mode 100644
index 1ef9bf1..0000000
--- a/contrib/llvm/tools/llvm-ld/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-##===- tools/llvm-ld/Makefile ------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-
-TOOLNAME = llvm-ld
-LINK_COMPONENTS = ipo scalaropts linker archive bitwriter
-
-include $(LEVEL)/Makefile.common
diff --git a/contrib/llvm/tools/llvm-ld/llvm-ld.cpp b/contrib/llvm/tools/llvm-ld/llvm-ld.cpp
index 6b4c3c7..ecf0476 100644
--- a/contrib/llvm/tools/llvm-ld/llvm-ld.cpp
+++ b/contrib/llvm/tools/llvm-ld/llvm-ld.cpp
@@ -37,7 +37,6 @@
#include "llvm/Support/SystemUtils.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/Signals.h"
-#include "llvm/Config/config.h"
#include <memory>
#include <cstring>
using namespace llvm;
@@ -424,7 +423,7 @@ static void EmitShellScript(char **argv, Module *M) {
PrintAndExit(ErrMsg, M);
return;
-#endif
+#else
// Output the script to start the program...
std::string ErrorInfo;
@@ -470,6 +469,7 @@ static void EmitShellScript(char **argv, Module *M) {
}
Out2.os() << " " << BitcodeOutputFilename << " ${1+\"$@\"}\n";
Out2.keep();
+#endif
}
// BuildLinkItems -- This function generates a LinkItemList for the LinkItems
diff --git a/contrib/llvm/tools/llvm-link/CMakeLists.txt b/contrib/llvm/tools/llvm-link/CMakeLists.txt
deleted file mode 100644
index 11933f7..0000000
--- a/contrib/llvm/tools/llvm-link/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-set(LLVM_LINK_COMPONENTS linker bitreader bitwriter asmparser)
-
-add_llvm_tool(llvm-link
- llvm-link.cpp
- )
diff --git a/contrib/llvm/tools/llvm-link/Makefile b/contrib/llvm/tools/llvm-link/Makefile
deleted file mode 100644
index 2637018..0000000
--- a/contrib/llvm/tools/llvm-link/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-##===- tools/llvm-link/Makefile ----------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-LEVEL = ../..
-
-TOOLNAME = llvm-link
-LINK_COMPONENTS = linker bitreader bitwriter asmparser
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-include $(LEVEL)/Makefile.common
diff --git a/contrib/llvm/tools/llvm-link/llvm-link.cpp b/contrib/llvm/tools/llvm-link/llvm-link.cpp
index 95ad1ca..378a833 100644
--- a/contrib/llvm/tools/llvm-link/llvm-link.cpp
+++ b/contrib/llvm/tools/llvm-link/llvm-link.cpp
@@ -69,7 +69,7 @@ static inline std::auto_ptr<Module> LoadFile(const char *argv0,
Result = ParseIRFile(FNStr, Err, Context);
if (Result) return std::auto_ptr<Module>(Result); // Load successful!
- Err.Print(argv0, errs());
+ Err.print(argv0, errs());
return std::auto_ptr<Module>();
}
diff --git a/contrib/llvm/tools/llvm-mc/CMakeLists.txt b/contrib/llvm/tools/llvm-mc/CMakeLists.txt
deleted file mode 100644
index 805caf4..0000000
--- a/contrib/llvm/tools/llvm-mc/CMakeLists.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support MC MCParser MCDisassembler)
-
-add_llvm_tool(llvm-mc
- llvm-mc.cpp
- Disassembler.cpp
- )
diff --git a/contrib/llvm/tools/llvm-mc/Disassembler.cpp b/contrib/llvm/tools/llvm-mc/Disassembler.cpp
index a9381b5..a8cd7c1 100644
--- a/contrib/llvm/tools/llvm-mc/Disassembler.cpp
+++ b/contrib/llvm/tools/llvm-mc/Disassembler.cpp
@@ -21,6 +21,8 @@
#include "llvm/MC/MCDisassembler.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/Triple.h"
@@ -72,14 +74,16 @@ static bool PrintInsts(const MCDisassembler &DisAsm,
switch (S) {
case MCDisassembler::Fail:
SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second),
- "invalid instruction encoding", "warning");
+ SourceMgr::DK_Warning,
+ "invalid instruction encoding");
if (Size == 0)
Size = 1; // skip illegible bytes
break;
case MCDisassembler::SoftFail:
SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second),
- "potentially undefined instruction encoding", "warning");
+ SourceMgr::DK_Warning,
+ "potentially undefined instruction encoding");
// Fall through
case MCDisassembler::Success:
@@ -125,8 +129,8 @@ static bool ByteArrayFromString(ByteArrayTy &ByteArray,
unsigned ByteVal;
if (Value.getAsInteger(0, ByteVal) || ByteVal > 255) {
// If we have an error, print it and skip to the end of line.
- SM.PrintMessage(SMLoc::getFromPointer(Value.data()),
- "invalid input token", "error");
+ SM.PrintMessage(SMLoc::getFromPointer(Value.data()), SourceMgr::DK_Error,
+ "invalid input token");
Str = Str.substr(Str.find('\n'));
ByteArray.clear();
continue;
@@ -153,21 +157,34 @@ int Disassembler::disassemble(const Target &T,
return -1;
}
- OwningPtr<const MCSubtargetInfo> STI(T.createMCSubtargetInfo(Triple, Cpu, FeaturesStr));
+ OwningPtr<const MCSubtargetInfo> STI(T.createMCSubtargetInfo(Triple, Cpu,
+ FeaturesStr));
if (!STI) {
errs() << "error: no subtarget info for target " << Triple << "\n";
return -1;
}
-
+
OwningPtr<const MCDisassembler> DisAsm(T.createMCDisassembler(*STI));
if (!DisAsm) {
errs() << "error: no disassembler for target " << Triple << "\n";
return -1;
}
+ OwningPtr<const MCRegisterInfo> MRI(T.createMCRegInfo(Triple));
+ if (!MRI) {
+ errs() << "error: no register info for target " << Triple << "\n";
+ return -1;
+ }
+
+ OwningPtr<const MCInstrInfo> MII(T.createMCInstrInfo());
+ if (!MII) {
+ errs() << "error: no instruction info for target " << Triple << "\n";
+ return -1;
+ }
+
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
- OwningPtr<MCInstPrinter> IP(T.createMCInstPrinter(AsmPrinterVariant,
- *AsmInfo, *STI));
+ OwningPtr<MCInstPrinter> IP(T.createMCInstPrinter(AsmPrinterVariant, *AsmInfo,
+ *MII, *MRI, *STI));
if (!IP) {
errs() << "error: no instruction printer for target " << Triple << '\n';
return -1;
@@ -247,7 +264,6 @@ int Disassembler::disassembleEnhanced(const std::string &TS,
break;
}
- EDDisassembler::initialize();
OwningPtr<EDDisassembler>
disassembler(EDDisassembler::getDisassembler(TS.c_str(), AS));
@@ -294,7 +310,6 @@ int Disassembler::disassembleEnhanced(const std::string &TS,
Out << operandIndex << "-";
switch (token->type()) {
- default: Out << "?"; break;
case EDToken::kTokenWhitespace: Out << "w"; break;
case EDToken::kTokenPunctuation: Out << "p"; break;
case EDToken::kTokenOpcode: Out << "o"; break;
@@ -365,4 +380,3 @@ int Disassembler::disassembleEnhanced(const std::string &TS,
return 0;
}
-
diff --git a/contrib/llvm/tools/llvm-mc/Makefile b/contrib/llvm/tools/llvm-mc/Makefile
deleted file mode 100644
index 934a6e4..0000000
--- a/contrib/llvm/tools/llvm-mc/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-##===- tools/llvm-mc/Makefile ------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = llvm-mc
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-# Include this here so we can get the configuration of the targets
-# that have been configured for construction. We have to do this
-# early so we can set up LINK_COMPONENTS before including Makefile.rules
-include $(LEVEL)/Makefile.config
-
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) MCDisassembler MCParser MC support
-
-include $(LLVM_SRC_ROOT)/Makefile.rules
-
diff --git a/contrib/llvm/tools/llvm-mc/llvm-mc.cpp b/contrib/llvm/tools/llvm-mc/llvm-mc.cpp
index 5fb3fdf..d882e01 100644
--- a/contrib/llvm/tools/llvm-mc/llvm-mc.cpp
+++ b/contrib/llvm/tools/llvm-mc/llvm-mc.cpp
@@ -70,9 +70,6 @@ RelaxAll("mc-relax-all", cl::desc("Relax all fixups"));
static cl::opt<bool>
NoExecStack("mc-no-exec-stack", cl::desc("File doesn't need an exec stack"));
-static cl::opt<bool>
-EnableLogging("enable-api-logging", cl::desc("Enable MC API logging"));
-
enum OutputFileType {
OFT_Null,
OFT_AssemblyFile,
@@ -152,6 +149,10 @@ NoInitialTextSection("n", cl::desc("Don't assume assembly file starts "
static cl::opt<bool>
SaveTempLabels("L", cl::desc("Don't discard temporary labels"));
+static cl::opt<bool>
+GenDwarfForAssembly("g", cl::desc("Generate dwarf debugging info for assembly "
+ "source files"));
+
enum ActionType {
AC_AsLex,
AC_Assemble,
@@ -175,7 +176,7 @@ Action(cl::desc("Action to perform:"),
static const Target *GetTarget(const char *ProgName) {
// Figure out the target triple.
if (TripleName.empty())
- TripleName = sys::getHostTriple();
+ TripleName = sys::getDefaultTargetTriple();
Triple TheTriple(Triple::normalize(TripleName));
const Target *TheTarget = 0;
@@ -230,6 +231,17 @@ static tool_output_file *GetOutputStream() {
return Out;
}
+static std::string DwarfDebugFlags;
+static void setDwarfDebugFlags(int argc, char **argv) {
+ if (!getenv("RC_DEBUG_OPTIONS"))
+ return;
+ for (int i = 0; i < argc; i++) {
+ DwarfDebugFlags += argv[i];
+ if (i + 1 < argc)
+ DwarfDebugFlags += " ";
+ }
+}
+
static int AsLexInput(const char *ProgName) {
OwningPtr<MemoryBuffer> BufferPtr;
if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, BufferPtr)) {
@@ -267,7 +279,8 @@ static int AsLexInput(const char *ProgName) {
switch (Tok.getKind()) {
default:
- SrcMgr.PrintMessage(Lexer.getLoc(), "unknown token", "warning");
+ SrcMgr.PrintMessage(Lexer.getLoc(), SourceMgr::DK_Warning,
+ "unknown token");
Error = true;
break;
case AsmToken::Error:
@@ -370,12 +383,16 @@ static int AssembleInput(const char *ProgName) {
// 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);
MOFI->InitMCObjectFileInfo(TripleName, RelocModel, CMModel, Ctx);
if (SaveTempLabels)
Ctx.setAllowTemporaryLabels(false);
+ Ctx.setGenDwarfForAssembly(GenDwarfForAssembly);
+ if (!DwarfDebugFlags.empty())
+ Ctx.setDwarfDebugFlags(StringRef(DwarfDebugFlags));
+
// Package up features to be passed to target/subtarget
std::string FeaturesStr;
if (MAttrs.size()) {
@@ -399,7 +416,7 @@ static int AssembleInput(const char *ProgName) {
// FIXME: There is a bit of code duplication with addPassesToEmitFile.
if (FileType == OFT_AssemblyFile) {
MCInstPrinter *IP =
- TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI, *STI);
+ TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI, *MCII, *MRI, *STI);
MCCodeEmitter *CE = 0;
MCAsmBackend *MAB = 0;
if (ShowEncoding) {
@@ -408,8 +425,10 @@ static int AssembleInput(const char *ProgName) {
}
Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/true,
/*useLoc*/ true,
- /*useCFI*/ true, IP, CE, MAB,
- ShowInst));
+ /*useCFI*/ true,
+ /*useDwarfDirectory*/ true,
+ IP, CE, MAB, ShowInst));
+
} else if (FileType == OFT_Null) {
Str.reset(createNullStreamer(Ctx));
} else {
@@ -421,10 +440,6 @@ static int AssembleInput(const char *ProgName) {
NoExecStack));
}
- if (EnableLogging) {
- Str.reset(createLoggingStreamer(Str.take(), errs()));
- }
-
OwningPtr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx,
*Str.get(), *MAI));
OwningPtr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(*STI, *Parser));
@@ -497,11 +512,14 @@ int main(int argc, char **argv) {
llvm::InitializeAllAsmParsers();
llvm::InitializeAllDisassemblers();
+ // Register the target printer for --version.
+ cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
+
cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n");
TripleName = Triple::normalize(TripleName);
+ setDwarfDebugFlags(argc, argv);
switch (Action) {
- default:
case AC_AsLex:
return AsLexInput(argv[0]);
case AC_Assemble:
@@ -511,7 +529,4 @@ int main(int argc, char **argv) {
case AC_EDisassemble:
return DisassembleInput(argv[0], true);
}
-
- return 0;
}
-
diff --git a/contrib/llvm/tools/llvm-nm/CMakeLists.txt b/contrib/llvm/tools/llvm-nm/CMakeLists.txt
deleted file mode 100644
index b6cd80b..0000000
--- a/contrib/llvm/tools/llvm-nm/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-set(LLVM_LINK_COMPONENTS archive bitreader object)
-
-add_llvm_tool(llvm-nm
- llvm-nm.cpp
- )
diff --git a/contrib/llvm/tools/llvm-nm/Makefile b/contrib/llvm/tools/llvm-nm/Makefile
deleted file mode 100644
index 6bb4cd4..0000000
--- a/contrib/llvm/tools/llvm-nm/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-##===- tools/llvm-nm/Makefile ------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-LEVEL = ../..
-
-TOOLNAME = llvm-nm
-LINK_COMPONENTS = archive bitreader object
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-include $(LEVEL)/Makefile.common
diff --git a/contrib/llvm/tools/llvm-nm/llvm-nm.cpp b/contrib/llvm/tools/llvm-nm/llvm-nm.cpp
index e79d72d..8d9e51e 100644
--- a/contrib/llvm/tools/llvm-nm/llvm-nm.cpp
+++ b/contrib/llvm/tools/llvm-nm/llvm-nm.cpp
@@ -27,6 +27,7 @@
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/Format.h"
@@ -60,6 +61,12 @@ namespace {
cl::alias UndefinedOnly2("u", cl::desc("Alias for --undefined-only"),
cl::aliasopt(UndefinedOnly));
+ cl::opt<bool> DynamicSyms("dynamic",
+ cl::desc("Display the dynamic symbols instead "
+ "of normal symbols."));
+ cl::alias DynamicSyms2("D", cl::desc("Alias for --dynamic"),
+ cl::aliasopt(DynamicSyms));
+
cl::opt<bool> DefinedOnly("defined-only",
cl::desc("Show only defined symbols"));
@@ -110,6 +117,19 @@ namespace {
std::string ToolName;
}
+
+static void error(Twine message, Twine path = Twine()) {
+ errs() << ToolName << ": " << path << ": " << message << ".\n";
+}
+
+static bool error(error_code ec, Twine path = Twine()) {
+ if (ec) {
+ error(ec.message(), path);
+ return true;
+ }
+ return false;
+}
+
namespace {
struct NMSymbol {
uint64_t Address;
@@ -144,14 +164,6 @@ namespace {
StringRef CurrentFilename;
typedef std::vector<NMSymbol> SymbolListT;
SymbolListT SymbolList;
-
- bool error(error_code ec) {
- if (!ec) return false;
-
- outs() << ToolName << ": error reading file: " << ec.message() << ".\n";
- outs().flush();
- return true;
- }
}
static void SortAndPrintSymbolList() {
@@ -192,9 +204,10 @@ static void SortAndPrintSymbolList() {
strcpy(SymbolSizeStr, " ");
if (i->Address != object::UnknownAddressOrSize)
- format("%08"PRIx64, i->Address).print(SymbolAddrStr, sizeof(SymbolAddrStr));
+ format("%08" PRIx64, i->Address).print(SymbolAddrStr,
+ sizeof(SymbolAddrStr));
if (i->Size != object::UnknownAddressOrSize)
- format("%08"PRIx64, i->Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
+ format("%08" PRIx64, i->Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
if (OutputFormat == posix) {
outs() << i->Name << " " << i->TypeChar << " "
@@ -271,13 +284,17 @@ static void DumpSymbolNamesFromModule(Module *M) {
static void DumpSymbolNamesFromObject(ObjectFile *obj) {
error_code ec;
- for (symbol_iterator i = obj->begin_symbols(),
- e = obj->end_symbols();
- i != e; i.increment(ec)) {
+ symbol_iterator ibegin = obj->begin_symbols();
+ symbol_iterator iend = obj->end_symbols();
+ if (DynamicSyms) {
+ ibegin = obj->begin_dynamic_symbols();
+ iend = obj->end_dynamic_symbols();
+ }
+ for (symbol_iterator i = ibegin; i != iend; i.increment(ec)) {
if (error(ec)) break;
- bool internal;
- if (error(i->isInternal(internal))) break;
- if (!DebugSyms && internal)
+ uint32_t symflags;
+ if (error(i->getFlags(symflags))) break;
+ if (!DebugSyms && (symflags & SymbolRef::SF_FormatSpecific))
continue;
NMSymbol s;
s.Size = object::UnknownAddressOrSize;
@@ -286,7 +303,7 @@ static void DumpSymbolNamesFromObject(ObjectFile *obj) {
if (error(i->getSize(s.Size))) break;
}
if (PrintAddress)
- if (error(i->getOffset(s.Address))) break;
+ if (error(i->getAddress(s.Address))) break;
if (error(i->getNMTypeChar(s.TypeChar))) break;
if (error(i->getName(s.Name))) break;
SymbolList.push_back(s);
@@ -297,38 +314,39 @@ static void DumpSymbolNamesFromObject(ObjectFile *obj) {
}
static void DumpSymbolNamesFromFile(std::string &Filename) {
+ if (Filename != "-" && !sys::fs::exists(Filename)) {
+ errs() << ToolName << ": '" << Filename << "': " << "No such file\n";
+ return;
+ }
+
+ OwningPtr<MemoryBuffer> Buffer;
+ if (error(MemoryBuffer::getFileOrSTDIN(Filename, Buffer), Filename))
+ return;
+
+ sys::fs::file_magic magic = sys::fs::identify_magic(Buffer->getBuffer());
+
LLVMContext &Context = getGlobalContext();
std::string ErrorMessage;
- sys::Path aPath(Filename);
- bool exists;
- if (sys::fs::exists(aPath.str(), exists) || !exists)
- errs() << ToolName << ": '" << Filename << "': " << "No such file\n";
- // Note: Currently we do not support reading an archive from stdin.
- if (Filename == "-" || aPath.isBitcodeFile()) {
- OwningPtr<MemoryBuffer> Buffer;
- if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buffer))
- ErrorMessage = ec.message();
+ if (magic == sys::fs::file_magic::bitcode) {
Module *Result = 0;
- if (Buffer.get())
- Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage);
-
+ Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage);
if (Result) {
DumpSymbolNamesFromModule(Result);
delete Result;
- } else
- errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n";
-
- } else if (aPath.isArchive()) {
- OwningPtr<Binary> arch;
- if (error_code ec = object::createBinary(aPath.str(), arch)) {
- errs() << ToolName << ": " << Filename << ": " << ec.message() << ".\n";
+ } else {
+ error(ErrorMessage, Filename);
return;
}
+ } else if (magic == sys::fs::file_magic::archive) {
+ OwningPtr<Binary> arch;
+ if (error(object::createBinary(Buffer.take(), arch), Filename))
+ return;
+
if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) {
for (object::Archive::child_iterator i = a->begin_children(),
e = a->end_children(); i != e; ++i) {
OwningPtr<Binary> child;
- if (error_code ec = i->getAsBinary(child)) {
+ if (i->getAsBinary(child)) {
// Try opening it as a bitcode file.
OwningPtr<MemoryBuffer> buff(i->getBuffer());
Module *Result = 0;
@@ -347,12 +365,10 @@ static void DumpSymbolNamesFromFile(std::string &Filename) {
}
}
}
- } else if (aPath.isObjectFile()) {
+ } else if (magic.is_object()) {
OwningPtr<Binary> obj;
- if (error_code ec = object::createBinary(aPath.str(), obj)) {
- errs() << ToolName << ": " << Filename << ": " << ec.message() << ".\n";
+ if (error(object::createBinary(Buffer.take(), obj), Filename))
return;
- }
if (object::ObjectFile *o = dyn_cast<ObjectFile>(obj.get()))
DumpSymbolNamesFromObject(o);
} else {
@@ -370,6 +386,10 @@ int main(int argc, char **argv) {
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n");
+ // llvm-nm only reads binary files.
+ if (error(sys::Program::ChangeStdinToBinary()))
+ return 1;
+
ToolName = argv[0];
if (BSDFormat) OutputFormat = bsd;
if (POSIXFormat) OutputFormat = posix;
diff --git a/contrib/llvm/tools/llvm-objdump/CMakeLists.txt b/contrib/llvm/tools/llvm-objdump/CMakeLists.txt
deleted file mode 100644
index f3b2e1f..0000000
--- a/contrib/llvm/tools/llvm-objdump/CMakeLists.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-set(LLVM_LINK_COMPONENTS
- ${LLVM_TARGETS_TO_BUILD}
- DebugInfo
- MC
- MCParser
- MCDisassembler
- Object
- )
-
-add_llvm_tool(llvm-objdump
- llvm-objdump.cpp
- MachODump.cpp
- MCFunction.cpp
- )
diff --git a/contrib/llvm/tools/llvm-objdump/MachODump.cpp b/contrib/llvm/tools/llvm-objdump/MachODump.cpp
index 3f44b29..0e7f3fd 100644
--- a/contrib/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/contrib/llvm/tools/llvm-objdump/MachODump.cpp
@@ -14,7 +14,7 @@
#include "llvm-objdump.h"
#include "MCFunction.h"
#include "llvm/Support/MachO.h"
-#include "llvm/Object/MachOObject.h"
+#include "llvm/Object/MachO.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/STLExtras.h"
@@ -26,6 +26,7 @@
#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
@@ -53,27 +54,28 @@ static cl::opt<std::string>
static const Target *GetTarget(const MachOObject *MachOObj) {
// Figure out the target triple.
- llvm::Triple TT("unknown-unknown-unknown");
- switch (MachOObj->getHeader().CPUType) {
- case llvm::MachO::CPUTypeI386:
- TT.setArch(Triple::ArchType(Triple::x86));
- break;
- case llvm::MachO::CPUTypeX86_64:
- TT.setArch(Triple::ArchType(Triple::x86_64));
- break;
- case llvm::MachO::CPUTypeARM:
- TT.setArch(Triple::ArchType(Triple::arm));
- break;
- case llvm::MachO::CPUTypePowerPC:
- TT.setArch(Triple::ArchType(Triple::ppc));
- break;
- case llvm::MachO::CPUTypePowerPC64:
- TT.setArch(Triple::ArchType(Triple::ppc64));
- break;
+ if (TripleName.empty()) {
+ llvm::Triple TT("unknown-unknown-unknown");
+ switch (MachOObj->getHeader().CPUType) {
+ case llvm::MachO::CPUTypeI386:
+ TT.setArch(Triple::ArchType(Triple::x86));
+ break;
+ case llvm::MachO::CPUTypeX86_64:
+ TT.setArch(Triple::ArchType(Triple::x86_64));
+ break;
+ case llvm::MachO::CPUTypeARM:
+ TT.setArch(Triple::ArchType(Triple::arm));
+ break;
+ case llvm::MachO::CPUTypePowerPC:
+ TT.setArch(Triple::ArchType(Triple::ppc));
+ break;
+ case llvm::MachO::CPUTypePowerPC64:
+ TT.setArch(Triple::ArchType(Triple::ppc64));
+ break;
+ }
+ TripleName = TT.str();
}
- TripleName = TT.str();
-
// Get the target specific parser.
std::string Error;
const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
@@ -85,57 +87,43 @@ static const Target *GetTarget(const MachOObject *MachOObj) {
return 0;
}
-struct Section {
- char Name[16];
- uint64_t Address;
- uint64_t Size;
- uint32_t Offset;
- uint32_t NumRelocs;
- uint64_t RelocTableOffset;
-};
-
-struct Symbol {
- uint64_t Value;
- uint32_t StringIndex;
- uint8_t SectionIndex;
- bool operator<(const Symbol &RHS) const { return Value < RHS.Value; }
+struct SymbolSorter {
+ bool operator()(const SymbolRef &A, const SymbolRef &B) {
+ SymbolRef::Type AType, BType;
+ A.getType(AType);
+ B.getType(BType);
+
+ uint64_t AAddr, BAddr;
+ if (AType != SymbolRef::ST_Function)
+ AAddr = 0;
+ else
+ A.getAddress(AAddr);
+ if (BType != SymbolRef::ST_Function)
+ BAddr = 0;
+ else
+ B.getAddress(BAddr);
+ return AAddr < BAddr;
+ }
};
-template <typename T>
-static Section copySection(const T &Sect) {
- Section S;
- memcpy(S.Name, Sect->Name, 16);
- S.Address = Sect->Address;
- S.Size = Sect->Size;
- S.Offset = Sect->Offset;
- S.NumRelocs = Sect->NumRelocationTableEntries;
- S.RelocTableOffset = Sect->RelocationTableOffset;
- return S;
-}
-
-template <typename T>
-static Symbol copySymbol(const T &STE) {
- Symbol S;
- S.StringIndex = STE->StringIndex;
- S.SectionIndex = STE->SectionIndex;
- S.Value = STE->Value;
- return S;
-}
-
// Print additional information about an address, if available.
-static void DumpAddress(uint64_t Address, ArrayRef<Section> Sections,
+static void DumpAddress(uint64_t Address, ArrayRef<SectionRef> Sections,
MachOObject *MachOObj, raw_ostream &OS) {
for (unsigned i = 0; i != Sections.size(); ++i) {
- uint64_t addr = Address-Sections[i].Address;
- if (Sections[i].Address <= Address &&
- Sections[i].Address + Sections[i].Size > Address) {
- StringRef bytes = MachOObj->getData(Sections[i].Offset,
- Sections[i].Size);
+ uint64_t SectAddr = 0, SectSize = 0;
+ Sections[i].getAddress(SectAddr);
+ Sections[i].getSize(SectSize);
+ uint64_t addr = SectAddr;
+ if (SectAddr <= Address &&
+ SectAddr + SectSize > Address) {
+ StringRef bytes, name;
+ Sections[i].getContents(bytes);
+ Sections[i].getName(name);
// Print constant strings.
- if (!strcmp(Sections[i].Name, "__cstring"))
+ if (!name.compare("__cstring"))
OS << '"' << bytes.substr(addr, bytes.find('\0', addr)) << '"';
// Print constant CFStrings.
- if (!strcmp(Sections[i].Name, "__cfstring"))
+ if (!name.compare("__cfstring"))
OS << "@\"" << bytes.substr(addr, bytes.find('\0', addr)) << '"';
}
}
@@ -212,59 +200,34 @@ static void emitDOTFile(const char *FileName, const MCFunction &f,
}
static void getSectionsAndSymbols(const macho::Header &Header,
- MachOObject *MachOObj,
+ MachOObjectFile *MachOObj,
InMemoryStruct<macho::SymtabLoadCommand> *SymtabLC,
- std::vector<Section> &Sections,
- std::vector<Symbol> &Symbols,
+ std::vector<SectionRef> &Sections,
+ std::vector<SymbolRef> &Symbols,
SmallVectorImpl<uint64_t> &FoundFns) {
- // Make a list of all symbols in the object file.
- for (unsigned i = 0; i != Header.NumLoadCommands; ++i) {
- const MachOObject::LoadCommandInfo &LCI = MachOObj->getLoadCommandInfo(i);
- if (LCI.Command.Type == macho::LCT_Segment) {
- InMemoryStruct<macho::SegmentLoadCommand> SegmentLC;
- MachOObj->ReadSegmentLoadCommand(LCI, SegmentLC);
-
- // Store the sections in this segment.
- for (unsigned SectNum = 0; SectNum != SegmentLC->NumSections; ++SectNum) {
- InMemoryStruct<macho::Section> Sect;
- MachOObj->ReadSection(LCI, SectNum, Sect);
- Sections.push_back(copySection(Sect));
+ error_code ec;
+ for (symbol_iterator SI = MachOObj->begin_symbols(),
+ SE = MachOObj->end_symbols(); SI != SE; SI.increment(ec))
+ Symbols.push_back(*SI);
+
+ for (section_iterator SI = MachOObj->begin_sections(),
+ SE = MachOObj->end_sections(); SI != SE; SI.increment(ec)) {
+ SectionRef SR = *SI;
+ StringRef SectName;
+ SR.getName(SectName);
+ Sections.push_back(*SI);
+ }
- }
- } else if (LCI.Command.Type == macho::LCT_Segment64) {
- InMemoryStruct<macho::Segment64LoadCommand> Segment64LC;
- MachOObj->ReadSegment64LoadCommand(LCI, Segment64LC);
-
- // Store the sections in this segment.
- for (unsigned SectNum = 0; SectNum != Segment64LC->NumSections;
- ++SectNum) {
- InMemoryStruct<macho::Section64> Sect64;
- MachOObj->ReadSection64(LCI, SectNum, Sect64);
- Sections.push_back(copySection(Sect64));
- }
- } else if (LCI.Command.Type == macho::LCT_FunctionStarts) {
+ for (unsigned i = 0; i != Header.NumLoadCommands; ++i) {
+ const MachOObject::LoadCommandInfo &LCI =
+ MachOObj->getObject()->getLoadCommandInfo(i);
+ if (LCI.Command.Type == macho::LCT_FunctionStarts) {
// We found a function starts segment, parse the addresses for later
// consumption.
InMemoryStruct<macho::LinkeditDataLoadCommand> LLC;
- MachOObj->ReadLinkeditDataLoadCommand(LCI, LLC);
+ MachOObj->getObject()->ReadLinkeditDataLoadCommand(LCI, LLC);
- MachOObj->ReadULEB128s(LLC->DataOffset, FoundFns);
- }
- }
- // Store the symbols.
- if (SymtabLC) {
- for (unsigned i = 0; i != (*SymtabLC)->NumSymbolTableEntries; ++i) {
- if (MachOObj->is64Bit()) {
- InMemoryStruct<macho::Symbol64TableEntry> STE;
- MachOObj->ReadSymbol64TableEntry((*SymtabLC)->SymbolTableOffset, i,
- STE);
- Symbols.push_back(copySymbol(STE));
- } else {
- InMemoryStruct<macho::SymbolTableEntry> STE;
- MachOObj->ReadSymbolTableEntry((*SymtabLC)->SymbolTableOffset, i,
- STE);
- Symbols.push_back(copySymbol(STE));
- }
+ MachOObj->getObject()->ReadULEB128s(LLC->DataOffset, FoundFns);
}
}
}
@@ -277,9 +240,11 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
return;
}
- OwningPtr<MachOObject> MachOObj(MachOObject::LoadFromBuffer(Buff.take()));
+ OwningPtr<MachOObjectFile> MachOOF(static_cast<MachOObjectFile*>(
+ ObjectFile::createMachOObjectFile(Buff.take())));
+ MachOObject *MachOObj = MachOOF->getObject();
- const Target *TheTarget = GetTarget(MachOObj.get());
+ const Target *TheTarget = GetTarget(MachOObj);
if (!TheTarget) {
// GetTarget prints out stuff.
return;
@@ -293,9 +258,11 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
OwningPtr<const MCSubtargetInfo>
STI(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
OwningPtr<const MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI));
+ OwningPtr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
- OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
- AsmPrinterVariant, *AsmInfo, *STI));
+ OwningPtr<MCInstPrinter>
+ IP(TheTarget->createMCInstPrinter(AsmPrinterVariant, *AsmInfo, *InstrInfo,
+ *MRI, *STI));
if (!InstrAnalysis || !AsmInfo || !STI || !DisAsm || !IP) {
errs() << "error: couldn't initialize disassembler for target "
@@ -322,17 +289,17 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
MachOObj->ReadSymtabLoadCommand(*SymtabLCI, SymtabLC);
MachOObj->RegisterStringTable(*SymtabLC);
- std::vector<Section> Sections;
- std::vector<Symbol> Symbols;
+ std::vector<SectionRef> Sections;
+ std::vector<SymbolRef> Symbols;
SmallVector<uint64_t, 8> FoundFns;
- getSectionsAndSymbols(Header, MachOObj.get(), &SymtabLC, Sections, Symbols,
+ getSectionsAndSymbols(Header, MachOOF.get(), &SymtabLC, Sections, Symbols,
FoundFns);
// Make a copy of the unsorted symbol list. FIXME: duplication
- std::vector<Symbol> UnsortedSymbols(Symbols);
+ std::vector<SymbolRef> UnsortedSymbols(Symbols);
// Sort the symbols by address, just in case they didn't come in that way.
- array_pod_sort(Symbols.begin(), Symbols.end());
+ std::sort(Symbols.begin(), Symbols.end(), SymbolSorter());
#ifndef NDEBUG
raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls();
@@ -343,12 +310,12 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
StringRef DebugAbbrevSection, DebugInfoSection, DebugArangesSection,
DebugLineSection, DebugStrSection;
OwningPtr<DIContext> diContext;
- OwningPtr<MachOObject> DSYMObj;
- MachOObject *DbgInfoObj = MachOObj.get();
+ OwningPtr<MachOObjectFile> DSYMObj;
+ MachOObject *DbgInfoObj = MachOObj;
// Try to find debug info and set up the DIContext for it.
if (UseDbg) {
- ArrayRef<Section> DebugSections = Sections;
- std::vector<Section> DSYMSections;
+ ArrayRef<SectionRef> DebugSections = Sections;
+ std::vector<SectionRef> DSYMSections;
// A separate DSym file path was specified, parse it as a macho file,
// get the sections and supply it to the section name parsing machinery.
@@ -358,34 +325,33 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
errs() << "llvm-objdump: " << Filename << ": " << ec.message() << '\n';
return;
}
- DSYMObj.reset(MachOObject::LoadFromBuffer(Buf.take()));
- const macho::Header &Header = DSYMObj->getHeader();
+ DSYMObj.reset(static_cast<MachOObjectFile*>(
+ ObjectFile::createMachOObjectFile(Buf.take())));
+ const macho::Header &Header = DSYMObj->getObject()->getHeader();
- std::vector<Symbol> Symbols;
+ std::vector<SymbolRef> Symbols;
SmallVector<uint64_t, 8> FoundFns;
getSectionsAndSymbols(Header, DSYMObj.get(), 0, DSYMSections, Symbols,
FoundFns);
DebugSections = DSYMSections;
- DbgInfoObj = DSYMObj.get();
+ DbgInfoObj = DSYMObj.get()->getObject();
}
// Find the named debug info sections.
for (unsigned SectIdx = 0; SectIdx != DebugSections.size(); SectIdx++) {
- if (!strcmp(DebugSections[SectIdx].Name, "__debug_abbrev"))
- DebugAbbrevSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset,
- DebugSections[SectIdx].Size);
- else if (!strcmp(DebugSections[SectIdx].Name, "__debug_info"))
- DebugInfoSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset,
- DebugSections[SectIdx].Size);
- else if (!strcmp(DebugSections[SectIdx].Name, "__debug_aranges"))
- DebugArangesSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset,
- DebugSections[SectIdx].Size);
- else if (!strcmp(DebugSections[SectIdx].Name, "__debug_line"))
- DebugLineSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset,
- DebugSections[SectIdx].Size);
- else if (!strcmp(DebugSections[SectIdx].Name, "__debug_str"))
- DebugStrSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset,
- DebugSections[SectIdx].Size);
+ StringRef SectName;
+ if (!DebugSections[SectIdx].getName(SectName)) {
+ if (SectName.equals("__DWARF,__debug_abbrev"))
+ DebugSections[SectIdx].getContents(DebugAbbrevSection);
+ else if (SectName.equals("__DWARF,__debug_info"))
+ DebugSections[SectIdx].getContents(DebugInfoSection);
+ else if (SectName.equals("__DWARF,__debug_aranges"))
+ DebugSections[SectIdx].getContents(DebugArangesSection);
+ else if (SectName.equals("__DWARF,__debug_line"))
+ DebugSections[SectIdx].getContents(DebugLineSection);
+ else if (SectName.equals("__DWARF,__debug_str"))
+ DebugSections[SectIdx].getContents(DebugStrSection);
+ }
}
// Setup the DIContext.
@@ -401,68 +367,115 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
FunctionListTy Functions;
for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {
- if (strcmp(Sections[SectIdx].Name, "__text"))
+ StringRef SectName;
+ if (Sections[SectIdx].getName(SectName) ||
+ SectName.compare("__TEXT,__text"))
continue; // Skip non-text sections
// Insert the functions from the function starts segment into our map.
- uint64_t VMAddr = Sections[SectIdx].Address - Sections[SectIdx].Offset;
- for (unsigned i = 0, e = FoundFns.size(); i != e; ++i)
- FunctionMap.insert(std::make_pair(FoundFns[i]+VMAddr, (MCFunction*)0));
+ uint64_t VMAddr;
+ Sections[SectIdx].getAddress(VMAddr);
+ for (unsigned i = 0, e = FoundFns.size(); i != e; ++i) {
+ StringRef SectBegin;
+ Sections[SectIdx].getContents(SectBegin);
+ uint64_t Offset = (uint64_t)SectBegin.data();
+ FunctionMap.insert(std::make_pair(VMAddr + FoundFns[i]-Offset,
+ (MCFunction*)0));
+ }
- StringRef Bytes = MachOObj->getData(Sections[SectIdx].Offset,
- Sections[SectIdx].Size);
+ StringRef Bytes;
+ Sections[SectIdx].getContents(Bytes);
StringRefMemoryObject memoryObject(Bytes);
bool symbolTableWorked = false;
// Parse relocations.
- std::vector<std::pair<uint64_t, uint32_t> > Relocs;
- for (unsigned j = 0; j != Sections[SectIdx].NumRelocs; ++j) {
- InMemoryStruct<macho::RelocationEntry> RE;
- MachOObj->ReadRelocationEntry(Sections[SectIdx].RelocTableOffset, j, RE);
- Relocs.push_back(std::make_pair(RE->Word0, RE->Word1 & 0xffffff));
+ std::vector<std::pair<uint64_t, SymbolRef> > Relocs;
+ error_code ec;
+ for (relocation_iterator RI = Sections[SectIdx].begin_relocations(),
+ RE = Sections[SectIdx].end_relocations(); RI != RE; RI.increment(ec)) {
+ uint64_t RelocOffset, SectionAddress;
+ RI->getAddress(RelocOffset);
+ Sections[SectIdx].getAddress(SectionAddress);
+ RelocOffset -= SectionAddress;
+
+ SymbolRef RelocSym;
+ RI->getSymbol(RelocSym);
+
+ Relocs.push_back(std::make_pair(RelocOffset, RelocSym));
}
array_pod_sort(Relocs.begin(), Relocs.end());
// Disassemble symbol by symbol.
for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {
+ StringRef SymName;
+ Symbols[SymIdx].getName(SymName);
+
+ SymbolRef::Type ST;
+ Symbols[SymIdx].getType(ST);
+ if (ST != SymbolRef::ST_Function)
+ continue;
+
// Make sure the symbol is defined in this section.
- if ((unsigned)Symbols[SymIdx].SectionIndex - 1 != SectIdx)
+ bool containsSym = false;
+ Sections[SectIdx].containsSymbol(Symbols[SymIdx], containsSym);
+ if (!containsSym)
continue;
// Start at the address of the symbol relative to the section's address.
- uint64_t Start = Symbols[SymIdx].Value - Sections[SectIdx].Address;
+ uint64_t SectionAddress = 0;
+ uint64_t Start = 0;
+ Sections[SectIdx].getAddress(SectionAddress);
+ Symbols[SymIdx].getAddress(Start);
+ Start -= SectionAddress;
+
// Stop disassembling either at the beginning of the next symbol or at
// the end of the section.
- uint64_t End = (SymIdx+1 == Symbols.size() ||
- Symbols[SymIdx].SectionIndex != Symbols[SymIdx+1].SectionIndex) ?
- Sections[SectIdx].Size :
- Symbols[SymIdx+1].Value - Sections[SectIdx].Address;
- uint64_t Size;
+ bool containsNextSym = true;
+ uint64_t NextSym = 0;
+ uint64_t NextSymIdx = SymIdx+1;
+ while (Symbols.size() > NextSymIdx) {
+ SymbolRef::Type NextSymType;
+ Symbols[NextSymIdx].getType(NextSymType);
+ if (NextSymType == SymbolRef::ST_Function) {
+ Sections[SectIdx].containsSymbol(Symbols[NextSymIdx],
+ containsNextSym);
+ Symbols[NextSymIdx].getAddress(NextSym);
+ NextSym -= SectionAddress;
+ break;
+ }
+ ++NextSymIdx;
+ }
- if (Start >= End)
- continue;
+ uint64_t SectSize;
+ Sections[SectIdx].getSize(SectSize);
+ uint64_t End = containsNextSym ? NextSym : SectSize;
+ uint64_t Size;
symbolTableWorked = true;
if (!CFG) {
// Normal disassembly, print addresses, bytes and mnemonic form.
- outs() << MachOObj->getStringAtIndex(Symbols[SymIdx].StringIndex)
- << ":\n";
+ StringRef SymName;
+ Symbols[SymIdx].getName(SymName);
+
+ outs() << SymName << ":\n";
DILineInfo lastLine;
for (uint64_t Index = Start; Index < End; Index += Size) {
MCInst Inst;
if (DisAsm->getInstruction(Inst, Size, memoryObject, Index,
DebugOut, nulls())) {
- outs() << format("%8llx:\t", Sections[SectIdx].Address + Index);
+ uint64_t SectAddress = 0;
+ Sections[SectIdx].getAddress(SectAddress);
+ outs() << format("%8" PRIx64 ":\t", SectAddress + Index);
+
DumpBytes(StringRef(Bytes.data() + Index, Size));
IP->printInst(&Inst, outs(), "");
// Print debug info.
if (diContext) {
DILineInfo dli =
- diContext->getLineInfoForAddress(Sections[SectIdx].Address +
- Index);
+ diContext->getLineInfoForAddress(SectAddress + Index);
// Print valid line info if it changed.
if (dli != lastLine && dli.getLine() != 0)
outs() << "\t## " << dli.getFileName() << ':'
@@ -478,20 +491,24 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
}
} else {
// Create CFG and use it for disassembly.
+ StringRef SymName;
+ Symbols[SymIdx].getName(SymName);
createMCFunctionAndSaveCalls(
- MachOObj->getStringAtIndex(Symbols[SymIdx].StringIndex),
- DisAsm.get(), memoryObject, Start, End, InstrAnalysis.get(),
- Start, DebugOut, FunctionMap, Functions);
+ SymName, DisAsm.get(), memoryObject, Start, End,
+ InstrAnalysis.get(), Start, DebugOut, FunctionMap, Functions);
}
}
if (CFG) {
if (!symbolTableWorked) {
// Reading the symbol table didn't work, create a big __TEXT symbol.
+ uint64_t SectSize = 0, SectAddress = 0;
+ Sections[SectIdx].getSize(SectSize);
+ Sections[SectIdx].getAddress(SectAddress);
createMCFunctionAndSaveCalls("__TEXT", DisAsm.get(), memoryObject,
- 0, Sections[SectIdx].Size,
+ 0, SectSize,
InstrAnalysis.get(),
- Sections[SectIdx].Offset, DebugOut,
+ SectAddress, DebugOut,
FunctionMap, Functions);
}
for (std::map<uint64_t, MCFunction*>::iterator mi = FunctionMap.begin(),
@@ -499,11 +516,14 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
if (mi->second == 0) {
// Create functions for the remaining callees we have gathered,
// but we didn't find a name for them.
+ uint64_t SectSize = 0;
+ Sections[SectIdx].getSize(SectSize);
+
SmallVector<uint64_t, 16> Calls;
MCFunction f =
MCFunction::createFunctionFromMC("unknown", DisAsm.get(),
memoryObject, mi->first,
- Sections[SectIdx].Size,
+ SectSize,
InstrAnalysis.get(), DebugOut,
Calls);
Functions.push_back(f);
@@ -535,13 +555,17 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
break;
}
+ uint64_t SectSize = 0, SectAddress;
+ Sections[SectIdx].getSize(SectSize);
+ Sections[SectIdx].getAddress(SectAddress);
+
// No predecessors, this is a data block. Print as .byte directives.
if (!hasPreds) {
- uint64_t End = llvm::next(fi) == fe ? Sections[SectIdx].Size :
+ uint64_t End = llvm::next(fi) == fe ? SectSize :
llvm::next(fi)->first;
outs() << "# " << End-fi->first << " bytes of data:\n";
for (unsigned pos = fi->first; pos != End; ++pos) {
- outs() << format("%8x:\t", Sections[SectIdx].Address + pos);
+ outs() << format("%8x:\t", SectAddress + pos);
DumpBytes(StringRef(Bytes.data() + pos, 1));
outs() << format("\t.byte 0x%02x\n", (uint8_t)Bytes[pos]);
}
@@ -558,13 +582,12 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
const MCDecodedInst &Inst = fi->second.getInsts()[ii];
// If there's a symbol at this address, print its name.
- if (FunctionMap.find(Sections[SectIdx].Address + Inst.Address) !=
+ if (FunctionMap.find(SectAddress + Inst.Address) !=
FunctionMap.end())
- outs() << FunctionMap[Sections[SectIdx].Address + Inst.Address]->
- getName() << ":\n";
+ outs() << FunctionMap[SectAddress + Inst.Address]-> getName()
+ << ":\n";
- outs() << format("%8llx:\t", Sections[SectIdx].Address +
- Inst.Address);
+ outs() << format("%8" PRIx64 ":\t", SectAddress + Inst.Address);
DumpBytes(StringRef(Bytes.data() + Inst.Address, Inst.Size));
if (fi->second.contains(fi->first)) // Indent simple loops.
@@ -575,15 +598,15 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
// Look for relocations inside this instructions, if there is one
// print its target and additional information if available.
for (unsigned j = 0; j != Relocs.size(); ++j)
- if (Relocs[j].first >= Sections[SectIdx].Address + Inst.Address &&
- Relocs[j].first < Sections[SectIdx].Address + Inst.Address +
- Inst.Size) {
- outs() << "\t# "
- << MachOObj->getStringAtIndex(
- UnsortedSymbols[Relocs[j].second].StringIndex)
- << ' ';
- DumpAddress(UnsortedSymbols[Relocs[j].second].Value, Sections,
- MachOObj.get(), outs());
+ if (Relocs[j].first >= SectAddress + Inst.Address &&
+ Relocs[j].first < SectAddress + Inst.Address + Inst.Size) {
+ StringRef SymName;
+ uint64_t Addr;
+ Relocs[j].second.getAddress(Addr);
+ Relocs[j].second.getName(SymName);
+
+ outs() << "\t# " << SymName << ' ';
+ DumpAddress(Addr, Sections, MachOObj, outs());
}
// If this instructions contains an address, see if we can evaluate
@@ -592,13 +615,12 @@ void llvm::DisassembleInputMachO(StringRef Filename) {
Inst.Address,
Inst.Size);
if (targ != -1ULL)
- DumpAddress(targ, Sections, MachOObj.get(), outs());
+ DumpAddress(targ, Sections, MachOObj, outs());
// Print debug info.
if (diContext) {
DILineInfo dli =
- diContext->getLineInfoForAddress(Sections[SectIdx].Address +
- Inst.Address);
+ diContext->getLineInfoForAddress(SectAddress + Inst.Address);
// Print valid line info if it changed.
if (dli != lastLine && dli.getLine() != 0)
outs() << "\t## " << dli.getFileName() << ':'
diff --git a/contrib/llvm/tools/llvm-objdump/Makefile b/contrib/llvm/tools/llvm-objdump/Makefile
deleted file mode 100644
index 703bf6c..0000000
--- a/contrib/llvm/tools/llvm-objdump/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-##===- tools/llvm-objdump/Makefile -------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-LEVEL = ../..
-
-TOOLNAME = llvm-objdump
-LINK_COMPONENTS = $(TARGETS_TO_BUILD) DebugInfo MC MCParser MCDisassembler \
- Object
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-include $(LEVEL)/Makefile.common
diff --git a/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp b/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 40c59bd..5a6f94a 100644
--- a/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -16,14 +16,18 @@
#include "llvm-objdump.h"
#include "MCFunction.h"
#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFF.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCDisassembler.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
@@ -43,6 +47,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
#include <algorithm>
+#include <cctype>
#include <cstring>
using namespace llvm;
using namespace object;
@@ -61,6 +66,12 @@ static cl::opt<bool>
Relocations("r", cl::desc("Display the relocation entries in the file"));
static cl::opt<bool>
+SectionContents("s", cl::desc("Display the content of each section"));
+
+static cl::opt<bool>
+SymbolTable("t", cl::desc("Display the symbol table"));
+
+static cl::opt<bool>
MachO("macho", cl::desc("Use MachO specific object file parser"));
static cl::alias
MachOm("m", cl::desc("Alias for --macho"), cl::aliasopt(MachO));
@@ -118,6 +129,8 @@ static const Target *GetTarget(const ObjectFile *Obj = NULL) {
return 0;
}
+void llvm::StringRefMemoryObject::anchor() { }
+
void llvm::DumpBytes(StringRef bytes) {
static const char hex_rep[] = "0123456789abcdef";
// FIXME: The real way to do this is to figure out the longest instruction
@@ -158,10 +171,6 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
return;
}
- outs() << '\n';
- outs() << Obj->getFileName()
- << ":\tfile format " << Obj->getFileFormatName() << "\n\n";
-
error_code ec;
for (section_iterator i = Obj->begin_sections(),
e = Obj->end_sections();
@@ -182,7 +191,9 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
bool contains;
if (!error(i->containsSymbol(*si, contains)) && contains) {
uint64_t Address;
- if (error(si->getOffset(Address))) break;
+ if (error(si->getAddress(Address))) break;
+ Address -= SectionAddr;
+
StringRef Name;
if (error(si->getName(Name))) break;
Symbols.push_back(std::make_pair(Address, Name));
@@ -238,9 +249,21 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
return;
}
+ OwningPtr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
+ if (!MRI) {
+ errs() << "error: no register info for target " << TripleName << "\n";
+ return;
+ }
+
+ OwningPtr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
+ if (!MII) {
+ errs() << "error: no instruction info for target " << TripleName << "\n";
+ return;
+ }
+
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
- AsmPrinterVariant, *AsmInfo, *STI));
+ AsmPrinterVariant, *AsmInfo, *MII, *MRI, *STI));
if (!IP) {
errs() << "error: no instruction printer for target " << TripleName
<< '\n';
@@ -285,7 +308,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
if (DisAsm->getInstruction(Inst, Size, memoryObject, Index,
DebugOut, nulls())) {
- outs() << format("%8"PRIx64":\t", SectionAddr + Index);
+ outs() << format("%8" PRIx64 ":\t", SectionAddr + Index);
DumpBytes(StringRef(Bytes.data() + Index, Size));
IP->printInst(&Inst, outs(), "");
outs() << "\n";
@@ -297,17 +320,23 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
// Print relocation for instruction.
while (rel_cur != rel_end) {
+ bool hidden = false;
uint64_t addr;
SmallString<16> name;
SmallString<32> val;
+
+ // If this relocation is hidden, skip it.
+ if (error(rel_cur->getHidden(hidden))) goto skip_print_rel;
+ if (hidden) goto skip_print_rel;
+
if (error(rel_cur->getAddress(addr))) goto skip_print_rel;
// Stop when rel_cur's address is past the current instruction.
- if (addr > Index + Size) break;
+ if (addr >= Index + Size) break;
if (error(rel_cur->getTypeName(name))) goto skip_print_rel;
if (error(rel_cur->getValueString(val))) goto skip_print_rel;
- outs() << format("\t\t\t%8"PRIx64": ", SectionAddr + addr) << name << "\t"
- << val << "\n";
+ outs() << format("\t\t\t%8" PRIx64 ": ", SectionAddr + addr) << name
+ << "\t" << val << "\n";
skip_print_rel:
++rel_cur;
@@ -332,9 +361,12 @@ static void PrintRelocations(const ObjectFile *o) {
ri != re; ri.increment(ec)) {
if (error(ec)) return;
+ bool hidden;
uint64_t address;
SmallString<32> relocname;
SmallString<32> valuestr;
+ if (error(ri->getHidden(hidden))) continue;
+ if (hidden) continue;
if (error(ri->getTypeName(relocname))) continue;
if (error(ri->getAddress(address))) continue;
if (error(ri->getValueString(valuestr))) continue;
@@ -364,19 +396,179 @@ static void PrintSectionHeaders(const ObjectFile *o) {
if (error(si->isBSS(BSS))) return;
std::string Type = (std::string(Text ? "TEXT " : "") +
(Data ? "DATA " : "") + (BSS ? "BSS" : ""));
- outs() << format("%3d %-13s %09"PRIx64" %017"PRIx64" %s\n", i, Name.str().c_str(), Size,
- Address, Type.c_str());
+ outs() << format("%3d %-13s %09" PRIx64 " %017" PRIx64 " %s\n",
+ i, Name.str().c_str(), Size, Address, Type.c_str());
++i;
}
}
+static void PrintSectionContents(const ObjectFile *o) {
+ error_code ec;
+ for (section_iterator si = o->begin_sections(),
+ se = o->end_sections();
+ si != se; si.increment(ec)) {
+ if (error(ec)) return;
+ StringRef Name;
+ StringRef Contents;
+ uint64_t BaseAddr;
+ if (error(si->getName(Name))) continue;
+ if (error(si->getContents(Contents))) continue;
+ if (error(si->getAddress(BaseAddr))) continue;
+
+ outs() << "Contents of section " << Name << ":\n";
+
+ // Dump out the content as hex and printable ascii characters.
+ for (std::size_t addr = 0, end = Contents.size(); addr < end; addr += 16) {
+ outs() << format(" %04" PRIx64 " ", BaseAddr + addr);
+ // Dump line of hex.
+ for (std::size_t i = 0; i < 16; ++i) {
+ if (i != 0 && i % 4 == 0)
+ outs() << ' ';
+ if (addr + i < end)
+ outs() << hexdigit((Contents[addr + i] >> 4) & 0xF, true)
+ << hexdigit(Contents[addr + i] & 0xF, true);
+ else
+ outs() << " ";
+ }
+ // Print ascii.
+ outs() << " ";
+ for (std::size_t i = 0; i < 16 && addr + i < end; ++i) {
+ if (std::isprint(Contents[addr + i] & 0xFF))
+ outs() << Contents[addr + i];
+ else
+ outs() << ".";
+ }
+ outs() << "\n";
+ }
+ }
+}
+
+static void PrintCOFFSymbolTable(const COFFObjectFile *coff) {
+ const coff_file_header *header;
+ if (error(coff->getHeader(header))) return;
+ int aux_count = 0;
+ const coff_symbol *symbol = 0;
+ for (int i = 0, e = header->NumberOfSymbols; i != e; ++i) {
+ if (aux_count--) {
+ // Figure out which type of aux this is.
+ if (symbol->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC
+ && symbol->Value == 0) { // Section definition.
+ const coff_aux_section_definition *asd;
+ if (error(coff->getAuxSymbol<coff_aux_section_definition>(i, asd)))
+ return;
+ outs() << "AUX "
+ << format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x "
+ , unsigned(asd->Length)
+ , unsigned(asd->NumberOfRelocations)
+ , unsigned(asd->NumberOfLinenumbers)
+ , unsigned(asd->CheckSum))
+ << format("assoc %d comdat %d\n"
+ , unsigned(asd->Number)
+ , unsigned(asd->Selection));
+ } else {
+ outs() << "AUX Unknown\n";
+ }
+ } else {
+ StringRef name;
+ if (error(coff->getSymbol(i, symbol))) return;
+ if (error(coff->getSymbolName(symbol, name))) return;
+ outs() << "[" << format("%2d", i) << "]"
+ << "(sec " << format("%2d", int(symbol->SectionNumber)) << ")"
+ << "(fl 0x00)" // Flag bits, which COFF doesn't have.
+ << "(ty " << format("%3x", unsigned(symbol->Type)) << ")"
+ << "(scl " << format("%3x", unsigned(symbol->StorageClass)) << ") "
+ << "(nx " << unsigned(symbol->NumberOfAuxSymbols) << ") "
+ << "0x" << format("%08x", unsigned(symbol->Value)) << " "
+ << name << "\n";
+ aux_count = symbol->NumberOfAuxSymbols;
+ }
+ }
+}
+
+static void PrintSymbolTable(const ObjectFile *o) {
+ outs() << "SYMBOL TABLE:\n";
+
+ if (const COFFObjectFile *coff = dyn_cast<const COFFObjectFile>(o))
+ PrintCOFFSymbolTable(coff);
+ else {
+ error_code ec;
+ for (symbol_iterator si = o->begin_symbols(),
+ se = o->end_symbols(); si != se; si.increment(ec)) {
+ if (error(ec)) return;
+ StringRef Name;
+ uint64_t Address;
+ SymbolRef::Type Type;
+ uint64_t Size;
+ uint32_t Flags;
+ section_iterator Section = o->end_sections();
+ if (error(si->getName(Name))) continue;
+ if (error(si->getAddress(Address))) continue;
+ if (error(si->getFlags(Flags))) continue;
+ if (error(si->getType(Type))) continue;
+ if (error(si->getSize(Size))) continue;
+ if (error(si->getSection(Section))) continue;
+
+ bool Global = Flags & SymbolRef::SF_Global;
+ bool Weak = Flags & SymbolRef::SF_Weak;
+ bool Absolute = Flags & SymbolRef::SF_Absolute;
+
+ if (Address == UnknownAddressOrSize)
+ Address = 0;
+ if (Size == UnknownAddressOrSize)
+ Size = 0;
+ char GlobLoc = ' ';
+ if (Type != SymbolRef::ST_Unknown)
+ GlobLoc = Global ? 'g' : 'l';
+ char Debug = (Type == SymbolRef::ST_Debug || Type == SymbolRef::ST_File)
+ ? 'd' : ' ';
+ char FileFunc = ' ';
+ if (Type == SymbolRef::ST_File)
+ FileFunc = 'f';
+ else if (Type == SymbolRef::ST_Function)
+ FileFunc = 'F';
+
+ outs() << format("%08" PRIx64, Address) << " "
+ << GlobLoc // Local -> 'l', Global -> 'g', Neither -> ' '
+ << (Weak ? 'w' : ' ') // Weak?
+ << ' ' // Constructor. Not supported yet.
+ << ' ' // Warning. Not supported yet.
+ << ' ' // Indirect reference to another symbol.
+ << Debug // Debugging (d) or dynamic (D) symbol.
+ << FileFunc // Name of function (F), file (f) or object (O).
+ << ' ';
+ if (Absolute)
+ outs() << "*ABS*";
+ else if (Section == o->end_sections())
+ outs() << "*UND*";
+ else {
+ StringRef SectionName;
+ if (error(Section->getName(SectionName)))
+ SectionName = "";
+ outs() << SectionName;
+ }
+ outs() << '\t'
+ << format("%08" PRIx64 " ", Size)
+ << Name
+ << '\n';
+ }
+ }
+}
+
static void DumpObject(const ObjectFile *o) {
+ outs() << '\n';
+ outs() << o->getFileName()
+ << ":\tfile format " << o->getFileFormatName() << "\n\n";
+
if (Disassemble)
DisassembleObject(o, Relocations);
if (Relocations && !Disassemble)
PrintRelocations(o);
if (SectionHeaders)
PrintSectionHeaders(o);
+ if (SectionContents)
+ PrintSectionContents(o);
+ if (SymbolTable)
+ PrintSymbolTable(o);
}
/// @brief Dump each object file in \a a;
@@ -385,8 +577,10 @@ static void DumpArchive(const Archive *a) {
e = a->end_children(); i != e; ++i) {
OwningPtr<Binary> child;
if (error_code ec = i->getAsBinary(child)) {
- errs() << ToolName << ": '" << a->getFileName() << "': " << ec.message()
- << ".\n";
+ // Ignore non-object files.
+ if (ec != object_error::invalid_file_type)
+ errs() << ToolName << ": '" << a->getFileName() << "': " << ec.message()
+ << ".\n";
continue;
}
if (ObjectFile *o = dyn_cast<ObjectFile>(child.get()))
@@ -447,7 +641,11 @@ int main(int argc, char **argv) {
if (InputFilenames.size() == 0)
InputFilenames.push_back("a.out");
- if (!Disassemble && !Relocations && !SectionHeaders) {
+ if (!Disassemble
+ && !Relocations
+ && !SectionHeaders
+ && !SectionContents
+ && !SymbolTable) {
cl::PrintHelpMessage();
return 2;
}
diff --git a/contrib/llvm/tools/llvm-objdump/llvm-objdump.h b/contrib/llvm/tools/llvm-objdump/llvm-objdump.h
index 75f852a..aa71b77 100644
--- a/contrib/llvm/tools/llvm-objdump/llvm-objdump.h
+++ b/contrib/llvm/tools/llvm-objdump/llvm-objdump.h
@@ -25,7 +25,7 @@ void DumpBytes(StringRef bytes);
void DisassembleInputMachO(StringRef Filename);
class StringRefMemoryObject : public MemoryObject {
-private:
+ virtual void anchor();
StringRef Bytes;
public:
StringRefMemoryObject(StringRef bytes) : Bytes(bytes) {}
diff --git a/contrib/llvm/tools/llvm-prof/CMakeLists.txt b/contrib/llvm/tools/llvm-prof/CMakeLists.txt
deleted file mode 100644
index 442112b..0000000
--- a/contrib/llvm/tools/llvm-prof/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-set(LLVM_LINK_COMPONENTS bitreader analysis)
-
-add_llvm_tool(llvm-prof
- llvm-prof.cpp
- )
diff --git a/contrib/llvm/tools/llvm-prof/Makefile b/contrib/llvm/tools/llvm-prof/Makefile
deleted file mode 100644
index 86eb54d..0000000
--- a/contrib/llvm/tools/llvm-prof/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-##===- tools/llvm-prof/Makefile ----------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-LEVEL = ../..
-
-TOOLNAME = llvm-prof
-LINK_COMPONENTS = bitreader analysis
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-include $(LEVEL)/Makefile.common
diff --git a/contrib/llvm/tools/llvm-prof/llvm-prof.cpp b/contrib/llvm/tools/llvm-prof/llvm-prof.cpp
index 9d0b468..d9b6713 100644
--- a/contrib/llvm/tools/llvm-prof/llvm-prof.cpp
+++ b/contrib/llvm/tools/llvm-prof/llvm-prof.cpp
@@ -200,9 +200,9 @@ bool ProfileInfoPrinterPass::runOnModule(Module &M) {
}
outs() << format("%3d", i+1) << ". "
- << format("%5.2g", FunctionCounts[i].second) << "/"
- << format("%g", TotalExecutions) << " "
- << FunctionCounts[i].first->getNameStr() << "\n";
+ << format("%5.2g", FunctionCounts[i].second) << "/"
+ << format("%g", TotalExecutions) << " "
+ << FunctionCounts[i].first->getName() << "\n";
}
std::set<Function*> FunctionsToPrint;
@@ -225,12 +225,12 @@ bool ProfileInfoPrinterPass::runOnModule(Module &M) {
for (unsigned i = 0; i != BlocksToPrint; ++i) {
if (Counts[i].second == 0) break;
Function *F = Counts[i].first->getParent();
- outs() << format("%3d", i+1) << ". "
- << format("%5g", Counts[i].second/(double)TotalExecutions*100) << "% "
- << format("%5.0f", Counts[i].second) << "/"
- << format("%g", TotalExecutions) << "\t"
- << F->getNameStr() << "() - "
- << Counts[i].first->getNameStr() << "\n";
+ outs() << format("%3d", i+1) << ". "
+ << format("%5g", Counts[i].second/(double)TotalExecutions*100)<<"% "
+ << format("%5.0f", Counts[i].second) << "/"
+ << format("%g", TotalExecutions) << "\t"
+ << F->getName() << "() - "
+ << Counts[i].first->getName() << "\n";
FunctionsToPrint.insert(F);
}
diff --git a/contrib/llvm/tools/llvm-ranlib/CMakeLists.txt b/contrib/llvm/tools/llvm-ranlib/CMakeLists.txt
deleted file mode 100644
index 3116d2e..0000000
--- a/contrib/llvm/tools/llvm-ranlib/CMakeLists.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-set(LLVM_LINK_COMPONENTS archive)
-set(LLVM_REQUIRES_EH 1)
-
-add_llvm_tool(llvm-ranlib
- llvm-ranlib.cpp
- )
diff --git a/contrib/llvm/tools/llvm-ranlib/Makefile b/contrib/llvm/tools/llvm-ranlib/Makefile
deleted file mode 100644
index 46a10e6..0000000
--- a/contrib/llvm/tools/llvm-ranlib/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-##===- tools/llvm-ranlib/Makefile --------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = llvm-ranlib
-LINK_COMPONENTS = archive
-REQUIRES_EH := 1
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-include $(LEVEL)/Makefile.common
diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp
new file mode 100644
index 0000000..3be1289
--- /dev/null
+++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -0,0 +1,218 @@
+//===- llvm-readobj.cpp - Dump contents of an Object File -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This program is a utility that works like traditional Unix "readelf",
+// except that it can handle any type of object file recognized by lib/Object.
+//
+// It makes use of the generic ObjectFile interface.
+//
+// Caution: This utility is new, experimental, unsupported, and incomplete.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Analysis/Verifier.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/FormattedStream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+static cl::opt<std::string>
+InputFilename(cl::Positional, cl::desc("<input object>"), cl::init(""));
+
+void DumpSymbolHeader() {
+ outs() << format(" %-32s", (const char*)"Name")
+ << format(" %-4s", (const char*)"Type")
+ << format(" %-16s", (const char*)"Address")
+ << format(" %-16s", (const char*)"Size")
+ << format(" %-16s", (const char*)"FileOffset")
+ << format(" %-26s", (const char*)"Flags")
+ << "\n";
+}
+
+const char *GetTypeStr(SymbolRef::Type Type) {
+ switch (Type) {
+ case SymbolRef::ST_Unknown: return "?";
+ case SymbolRef::ST_Data: return "DATA";
+ case SymbolRef::ST_Debug: return "DBG";
+ case SymbolRef::ST_File: return "FILE";
+ case SymbolRef::ST_Function: return "FUNC";
+ case SymbolRef::ST_Other: return "-";
+ }
+ return "INV";
+}
+
+std::string GetFlagStr(uint32_t Flags) {
+ std::string result;
+ if (Flags & SymbolRef::SF_Undefined)
+ result += "undef,";
+ if (Flags & SymbolRef::SF_Global)
+ result += "global,";
+ if (Flags & SymbolRef::SF_Weak)
+ result += "weak,";
+ if (Flags & SymbolRef::SF_Absolute)
+ result += "absolute,";
+ if (Flags & SymbolRef::SF_ThreadLocal)
+ result += "threadlocal,";
+ if (Flags & SymbolRef::SF_Common)
+ result += "common,";
+ if (Flags & SymbolRef::SF_FormatSpecific)
+ result += "formatspecific,";
+
+ // Remove trailing comma
+ if (result.size() > 0) {
+ result.erase(result.size() - 1);
+ }
+ return result;
+}
+
+void DumpSymbol(const SymbolRef &Sym, const ObjectFile *obj, bool IsDynamic) {
+ StringRef Name;
+ SymbolRef::Type Type;
+ uint32_t Flags;
+ uint64_t Address;
+ uint64_t Size;
+ uint64_t FileOffset;
+ Sym.getName(Name);
+ Sym.getAddress(Address);
+ Sym.getSize(Size);
+ Sym.getFileOffset(FileOffset);
+ Sym.getType(Type);
+ Sym.getFlags(Flags);
+ std::string FullName = Name;
+
+ // If this is a dynamic symbol from an ELF object, append
+ // the symbol's version to the name.
+ if (IsDynamic && obj->isELF()) {
+ StringRef Version;
+ bool IsDefault;
+ GetELFSymbolVersion(obj, Sym, Version, IsDefault);
+ if (!Version.empty()) {
+ FullName += (IsDefault ? "@@" : "@");
+ FullName += Version;
+ }
+ }
+
+ // format() can't handle StringRefs
+ outs() << format(" %-32s", FullName.c_str())
+ << format(" %-4s", GetTypeStr(Type))
+ << format(" %16" PRIx64, Address)
+ << format(" %16" PRIx64, Size)
+ << format(" %16" PRIx64, FileOffset)
+ << " " << GetFlagStr(Flags)
+ << "\n";
+}
+
+
+// Iterate through the normal symbols in the ObjectFile
+void DumpSymbols(const ObjectFile *obj) {
+ error_code ec;
+ uint32_t count = 0;
+ outs() << "Symbols:\n";
+ symbol_iterator it = obj->begin_symbols();
+ symbol_iterator ie = obj->end_symbols();
+ while (it != ie) {
+ DumpSymbol(*it, obj, false);
+ it.increment(ec);
+ if (ec)
+ report_fatal_error("Symbol iteration failed");
+ ++count;
+ }
+ outs() << " Total: " << count << "\n\n";
+}
+
+// Iterate through the dynamic symbols in the ObjectFile.
+void DumpDynamicSymbols(const ObjectFile *obj) {
+ error_code ec;
+ uint32_t count = 0;
+ outs() << "Dynamic Symbols:\n";
+ symbol_iterator it = obj->begin_dynamic_symbols();
+ symbol_iterator ie = obj->end_dynamic_symbols();
+ while (it != ie) {
+ DumpSymbol(*it, obj, true);
+ it.increment(ec);
+ if (ec)
+ report_fatal_error("Symbol iteration failed");
+ ++count;
+ }
+ outs() << " Total: " << count << "\n\n";
+}
+
+void DumpLibrary(const LibraryRef &lib) {
+ StringRef path;
+ lib.getPath(path);
+ outs() << " " << path << "\n";
+}
+
+// Iterate through needed libraries
+void DumpLibrariesNeeded(const ObjectFile *obj) {
+ error_code ec;
+ uint32_t count = 0;
+ library_iterator it = obj->begin_libraries_needed();
+ library_iterator ie = obj->end_libraries_needed();
+ outs() << "Libraries needed:\n";
+ while (it != ie) {
+ DumpLibrary(*it);
+ it.increment(ec);
+ if (ec)
+ report_fatal_error("Needed libraries iteration failed");
+ ++count;
+ }
+ outs() << " Total: " << count << "\n\n";
+}
+
+void DumpHeaders(const ObjectFile *obj) {
+ outs() << "File Format : " << obj->getFileFormatName() << "\n";
+ outs() << "Arch : "
+ << Triple::getArchTypeName((llvm::Triple::ArchType)obj->getArch())
+ << "\n";
+ outs() << "Address Size: " << (8*obj->getBytesInAddress()) << " bits\n";
+ outs() << "Load Name : " << obj->getLoadName() << "\n";
+ outs() << "\n";
+}
+
+int main(int argc, char** argv) {
+ error_code ec;
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+
+ cl::ParseCommandLineOptions(argc, argv,
+ "LLVM Object Reader\n");
+
+ if (InputFilename.empty()) {
+ errs() << "Please specify an input filename\n";
+ return 1;
+ }
+
+ // Open the object file
+ OwningPtr<MemoryBuffer> File;
+ if (MemoryBuffer::getFile(InputFilename, File)) {
+ errs() << InputFilename << ": Open failed\n";
+ return 1;
+ }
+
+ ObjectFile *obj = ObjectFile::createObjectFile(File.take());
+ if (!obj) {
+ errs() << InputFilename << ": Object type not recognized\n";
+ }
+
+ DumpHeaders(obj);
+ DumpSymbols(obj);
+ DumpDynamicSymbols(obj);
+ DumpLibrariesNeeded(obj);
+ return 0;
+}
+
diff --git a/contrib/llvm/tools/llvm-rtdyld/CMakeLists.txt b/contrib/llvm/tools/llvm-rtdyld/CMakeLists.txt
deleted file mode 100644
index 17e2c3e..0000000
--- a/contrib/llvm/tools/llvm-rtdyld/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support MC object RuntimeDyld JIT)
-
-add_llvm_tool(llvm-rtdyld
- llvm-rtdyld.cpp
- )
diff --git a/contrib/llvm/tools/llvm-rtdyld/Makefile b/contrib/llvm/tools/llvm-rtdyld/Makefile
deleted file mode 100644
index 0d57277..0000000
--- a/contrib/llvm/tools/llvm-rtdyld/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-##===- tools/llvm-rtdyld/Makefile --------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = llvm-rtdyld
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-# Include this here so we can get the configuration of the targets
-# that have been configured for construction. We have to do this
-# early so we can set up LINK_COMPONENTS before including Makefile.rules
-include $(LEVEL)/Makefile.config
-
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) support MC object RuntimeDyld JIT
-
-include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp b/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
index ec9d652..01a7d15 100644
--- a/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
+++ b/contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
@@ -51,22 +51,30 @@ EntryPoint("entry",
class TrivialMemoryManager : public RTDyldMemoryManager {
public:
SmallVector<sys::MemoryBlock, 16> FunctionMemory;
+ SmallVector<sys::MemoryBlock, 16> DataMemory;
+
+ uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
+ unsigned SectionID);
+ uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
+ unsigned SectionID);
+
+ virtual void *getPointerToNamedFunction(const std::string &Name,
+ bool AbortOnFailure = true) {
+ return 0;
+ }
- uint8_t *startFunctionBody(const char *Name, uintptr_t &Size);
- void endFunctionBody(const char *Name, uint8_t *FunctionStart,
- uint8_t *FunctionEnd);
};
-uint8_t *TrivialMemoryManager::startFunctionBody(const char *Name,
- uintptr_t &Size) {
+uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size,
+ unsigned Alignment,
+ unsigned SectionID) {
return (uint8_t*)sys::Memory::AllocateRWX(Size, 0, 0).base();
}
-void TrivialMemoryManager::endFunctionBody(const char *Name,
- uint8_t *FunctionStart,
- uint8_t *FunctionEnd) {
- uintptr_t Size = FunctionEnd - FunctionStart + 1;
- FunctionMemory.push_back(sys::MemoryBlock(FunctionStart, Size));
+uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size,
+ unsigned Alignment,
+ unsigned SectionID) {
+ return (uint8_t*)sys::Memory::AllocateRWX(Size, 0, 0).base();
}
static const char *ProgramName;
@@ -142,10 +150,7 @@ int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv, "llvm MC-JIT tool\n");
switch (Action) {
- default:
case AC_Execute:
return executeInput();
}
-
- return 0;
}
diff --git a/contrib/llvm/tools/llvm-stress/llvm-stress.cpp b/contrib/llvm/tools/llvm-stress/llvm-stress.cpp
new file mode 100644
index 0000000..d284ea5
--- /dev/null
+++ b/contrib/llvm/tools/llvm-stress/llvm-stress.cpp
@@ -0,0 +1,702 @@
+//===-- llvm-stress.cpp - Generate random LL files to stress-test LLVM ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This program is a utility that generates random .ll files to stress-test
+// different components in LLVM.
+//
+//===----------------------------------------------------------------------===//
+#include "llvm/LLVMContext.h"
+#include "llvm/Module.h"
+#include "llvm/PassManager.h"
+#include "llvm/Constants.h"
+#include "llvm/Instruction.h"
+#include "llvm/CallGraphSCCPass.h"
+#include "llvm/Assembly/PrintModulePass.h"
+#include "llvm/Analysis/Verifier.h"
+#include "llvm/Support/PassNameParser.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PluginLoader.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include <memory>
+#include <sstream>
+#include <set>
+#include <vector>
+#include <algorithm>
+using namespace llvm;
+
+static cl::opt<unsigned> SeedCL("seed",
+ cl::desc("Seed used for randomness"), cl::init(0));
+static cl::opt<unsigned> SizeCL("size",
+ cl::desc("The estimated size of the generated function (# of instrs)"),
+ cl::init(100));
+static cl::opt<std::string>
+OutputFilename("o", cl::desc("Override output filename"),
+ cl::value_desc("filename"));
+
+static cl::opt<bool> GenHalfFloat("generate-half-float",
+ cl::desc("Generate half-length floating-point values"), cl::init(false));
+static cl::opt<bool> GenX86FP80("generate-x86-fp80",
+ cl::desc("Generate 80-bit X86 floating-point values"), cl::init(false));
+static cl::opt<bool> GenFP128("generate-fp128",
+ cl::desc("Generate 128-bit floating-point values"), cl::init(false));
+static cl::opt<bool> GenPPCFP128("generate-ppc-fp128",
+ cl::desc("Generate 128-bit PPC floating-point values"), cl::init(false));
+static cl::opt<bool> GenX86MMX("generate-x86-mmx",
+ cl::desc("Generate X86 MMX floating-point values"), cl::init(false));
+
+/// A utility class to provide a pseudo-random number generator which is
+/// the same across all platforms. This is somewhat close to the libc
+/// implementation. Note: This is not a cryptographically secure pseudorandom
+/// number generator.
+class Random {
+public:
+ /// C'tor
+ Random(unsigned _seed):Seed(_seed) {}
+
+ /// Return a random integer, up to a
+ /// maximum of 2**19 - 1.
+ uint32_t Rand() {
+ uint32_t Val = Seed + 0x000b07a1;
+ Seed = (Val * 0x3c7c0ac1);
+ // Only lowest 19 bits are random-ish.
+ return Seed & 0x7ffff;
+ }
+
+ /// Return a random 32 bit integer.
+ uint32_t Rand32() {
+ uint32_t Val = Rand();
+ Val &= 0xffff;
+ return Val | (Rand() << 16);
+ }
+
+ /// Return a random 64 bit integer.
+ uint64_t Rand64() {
+ uint64_t Val = Rand32();
+ return Val | (uint64_t(Rand32()) << 32);
+ }
+private:
+ unsigned Seed;
+};
+
+/// Generate an empty function with a default argument list.
+Function *GenEmptyFunction(Module *M) {
+ // Type Definitions
+ std::vector<Type*> ArgsTy;
+ // Define a few arguments
+ LLVMContext &Context = M->getContext();
+ ArgsTy.push_back(PointerType::get(IntegerType::getInt8Ty(Context), 0));
+ ArgsTy.push_back(PointerType::get(IntegerType::getInt32Ty(Context), 0));
+ ArgsTy.push_back(PointerType::get(IntegerType::getInt64Ty(Context), 0));
+ ArgsTy.push_back(IntegerType::getInt32Ty(Context));
+ ArgsTy.push_back(IntegerType::getInt64Ty(Context));
+ ArgsTy.push_back(IntegerType::getInt8Ty(Context));
+
+ FunctionType *FuncTy = FunctionType::get(Type::getVoidTy(Context), ArgsTy, 0);
+ // Pick a unique name to describe the input parameters
+ std::stringstream ss;
+ ss<<"autogen_SD"<<SeedCL;
+ Function *Func = Function::Create(FuncTy, GlobalValue::ExternalLinkage,
+ ss.str(), M);
+
+ Func->setCallingConv(CallingConv::C);
+ return Func;
+}
+
+/// A base class, implementing utilities needed for
+/// modifying and adding new random instructions.
+struct Modifier {
+ /// Used to store the randomly generated values.
+ typedef std::vector<Value*> PieceTable;
+
+public:
+ /// C'tor
+ Modifier(BasicBlock *Block, PieceTable *PT, Random *R):
+ BB(Block),PT(PT),Ran(R),Context(BB->getContext()) {}
+ /// Add a new instruction.
+ virtual void Act() = 0;
+ /// Add N new instructions,
+ virtual void ActN(unsigned n) {
+ for (unsigned i=0; i<n; ++i)
+ Act();
+ }
+
+protected:
+ /// Return a random value from the list of known values.
+ Value *getRandomVal() {
+ assert(PT->size());
+ return PT->at(Ran->Rand() % PT->size());
+ }
+
+ Constant *getRandomConstant(Type *Tp) {
+ if (Tp->isIntegerTy()) {
+ if (Ran->Rand() & 1)
+ return ConstantInt::getAllOnesValue(Tp);
+ return ConstantInt::getNullValue(Tp);
+ } else if (Tp->isFloatingPointTy()) {
+ if (Ran->Rand() & 1)
+ return ConstantFP::getAllOnesValue(Tp);
+ return ConstantFP::getNullValue(Tp);
+ }
+ return UndefValue::get(Tp);
+ }
+
+ /// Return a random value with a known type.
+ Value *getRandomValue(Type *Tp) {
+ unsigned index = Ran->Rand();
+ for (unsigned i=0; i<PT->size(); ++i) {
+ Value *V = PT->at((index + i) % PT->size());
+ if (V->getType() == Tp)
+ return V;
+ }
+
+ // If the requested type was not found, generate a constant value.
+ if (Tp->isIntegerTy()) {
+ if (Ran->Rand() & 1)
+ return ConstantInt::getAllOnesValue(Tp);
+ return ConstantInt::getNullValue(Tp);
+ } else if (Tp->isFloatingPointTy()) {
+ if (Ran->Rand() & 1)
+ return ConstantFP::getAllOnesValue(Tp);
+ return ConstantFP::getNullValue(Tp);
+ } else if (Tp->isVectorTy()) {
+ VectorType *VTp = cast<VectorType>(Tp);
+
+ std::vector<Constant*> TempValues;
+ TempValues.reserve(VTp->getNumElements());
+ for (unsigned i = 0; i < VTp->getNumElements(); ++i)
+ TempValues.push_back(getRandomConstant(VTp->getScalarType()));
+
+ ArrayRef<Constant*> VectorValue(TempValues);
+ return ConstantVector::get(VectorValue);
+ }
+
+ return UndefValue::get(Tp);
+ }
+
+ /// Return a random value of any pointer type.
+ Value *getRandomPointerValue() {
+ unsigned index = Ran->Rand();
+ for (unsigned i=0; i<PT->size(); ++i) {
+ Value *V = PT->at((index + i) % PT->size());
+ if (V->getType()->isPointerTy())
+ return V;
+ }
+ return UndefValue::get(pickPointerType());
+ }
+
+ /// Return a random value of any vector type.
+ Value *getRandomVectorValue() {
+ unsigned index = Ran->Rand();
+ for (unsigned i=0; i<PT->size(); ++i) {
+ Value *V = PT->at((index + i) % PT->size());
+ if (V->getType()->isVectorTy())
+ return V;
+ }
+ return UndefValue::get(pickVectorType());
+ }
+
+ /// Pick a random type.
+ Type *pickType() {
+ return (Ran->Rand() & 1 ? pickVectorType() : pickScalarType());
+ }
+
+ /// Pick a random pointer type.
+ Type *pickPointerType() {
+ Type *Ty = pickType();
+ return PointerType::get(Ty, 0);
+ }
+
+ /// Pick a random vector type.
+ Type *pickVectorType(unsigned len = (unsigned)-1) {
+ // Pick a random vector width in the range 2**0 to 2**4.
+ // by adding two randoms we are generating a normal-like distribution
+ // around 2**3.
+ unsigned width = 1<<((Ran->Rand() % 3) + (Ran->Rand() % 3));
+ Type *Ty;
+
+ // Vectors of x86mmx are illegal; keep trying till we get something else.
+ do {
+ Ty = pickScalarType();
+ } while (Ty->isX86_MMXTy());
+
+ if (len != (unsigned)-1)
+ width = len;
+ return VectorType::get(Ty, width);
+ }
+
+ /// Pick a random scalar type.
+ Type *pickScalarType() {
+ Type *t = 0;
+ do {
+ switch (Ran->Rand() % 30) {
+ case 0: t = Type::getInt1Ty(Context); break;
+ case 1: t = Type::getInt8Ty(Context); break;
+ case 2: t = Type::getInt16Ty(Context); break;
+ case 3: case 4:
+ case 5: t = Type::getFloatTy(Context); break;
+ case 6: case 7:
+ case 8: t = Type::getDoubleTy(Context); break;
+ case 9: case 10:
+ case 11: t = Type::getInt32Ty(Context); break;
+ case 12: case 13:
+ case 14: t = Type::getInt64Ty(Context); break;
+ case 15: case 16:
+ case 17: if (GenHalfFloat) t = Type::getHalfTy(Context); break;
+ case 18: case 19:
+ case 20: if (GenX86FP80) t = Type::getX86_FP80Ty(Context); break;
+ case 21: case 22:
+ case 23: if (GenFP128) t = Type::getFP128Ty(Context); break;
+ case 24: case 25:
+ case 26: if (GenPPCFP128) t = Type::getPPC_FP128Ty(Context); break;
+ case 27: case 28:
+ case 29: if (GenX86MMX) t = Type::getX86_MMXTy(Context); break;
+ default: llvm_unreachable("Invalid scalar value");
+ }
+ } while (t == 0);
+
+ return t;
+ }
+
+ /// Basic block to populate
+ BasicBlock *BB;
+ /// Value table
+ PieceTable *PT;
+ /// Random number generator
+ Random *Ran;
+ /// Context
+ LLVMContext &Context;
+};
+
+struct LoadModifier: public Modifier {
+ LoadModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {}
+ virtual void Act() {
+ // Try to use predefined pointers. If non exist, use undef pointer value;
+ Value *Ptr = getRandomPointerValue();
+ Value *V = new LoadInst(Ptr, "L", BB->getTerminator());
+ PT->push_back(V);
+ }
+};
+
+struct StoreModifier: public Modifier {
+ StoreModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {}
+ virtual void Act() {
+ // Try to use predefined pointers. If non exist, use undef pointer value;
+ Value *Ptr = getRandomPointerValue();
+ Type *Tp = Ptr->getType();
+ Value *Val = getRandomValue(Tp->getContainedType(0));
+ Type *ValTy = Val->getType();
+
+ // Do not store vectors of i1s because they are unsupported
+ // by the codegen.
+ if (ValTy->isVectorTy() && ValTy->getScalarSizeInBits() == 1)
+ return;
+
+ new StoreInst(Val, Ptr, BB->getTerminator());
+ }
+};
+
+struct BinModifier: public Modifier {
+ BinModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {}
+
+ virtual void Act() {
+ Value *Val0 = getRandomVal();
+ Value *Val1 = getRandomValue(Val0->getType());
+
+ // Don't handle pointer types.
+ if (Val0->getType()->isPointerTy() ||
+ Val1->getType()->isPointerTy())
+ return;
+
+ // Don't handle i1 types.
+ if (Val0->getType()->getScalarSizeInBits() == 1)
+ return;
+
+
+ bool isFloat = Val0->getType()->getScalarType()->isFloatingPointTy();
+ Instruction* Term = BB->getTerminator();
+ unsigned R = Ran->Rand() % (isFloat ? 7 : 13);
+ Instruction::BinaryOps Op;
+
+ switch (R) {
+ default: llvm_unreachable("Invalid BinOp");
+ case 0:{Op = (isFloat?Instruction::FAdd : Instruction::Add); break; }
+ case 1:{Op = (isFloat?Instruction::FSub : Instruction::Sub); break; }
+ case 2:{Op = (isFloat?Instruction::FMul : Instruction::Mul); break; }
+ case 3:{Op = (isFloat?Instruction::FDiv : Instruction::SDiv); break; }
+ case 4:{Op = (isFloat?Instruction::FDiv : Instruction::UDiv); break; }
+ case 5:{Op = (isFloat?Instruction::FRem : Instruction::SRem); break; }
+ case 6:{Op = (isFloat?Instruction::FRem : Instruction::URem); break; }
+ case 7: {Op = Instruction::Shl; break; }
+ case 8: {Op = Instruction::LShr; break; }
+ case 9: {Op = Instruction::AShr; break; }
+ case 10:{Op = Instruction::And; break; }
+ case 11:{Op = Instruction::Or; break; }
+ case 12:{Op = Instruction::Xor; break; }
+ }
+
+ PT->push_back(BinaryOperator::Create(Op, Val0, Val1, "B", Term));
+ }
+};
+
+/// Generate constant values.
+struct ConstModifier: public Modifier {
+ ConstModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {}
+ virtual void Act() {
+ Type *Ty = pickType();
+
+ if (Ty->isVectorTy()) {
+ switch (Ran->Rand() % 2) {
+ case 0: if (Ty->getScalarType()->isIntegerTy())
+ return PT->push_back(ConstantVector::getAllOnesValue(Ty));
+ case 1: if (Ty->getScalarType()->isIntegerTy())
+ return PT->push_back(ConstantVector::getNullValue(Ty));
+ }
+ }
+
+ if (Ty->isFloatingPointTy()) {
+ // Generate 128 random bits, the size of the (currently)
+ // largest floating-point types.
+ uint64_t RandomBits[2];
+ for (unsigned i = 0; i < 2; ++i)
+ RandomBits[i] = Ran->Rand64();
+
+ APInt RandomInt(Ty->getPrimitiveSizeInBits(), makeArrayRef(RandomBits));
+
+ bool isIEEE = !Ty->isX86_FP80Ty() && !Ty->isPPC_FP128Ty();
+ APFloat RandomFloat(RandomInt, isIEEE);
+
+ if (Ran->Rand() & 1)
+ return PT->push_back(ConstantFP::getNullValue(Ty));
+ return PT->push_back(ConstantFP::get(Ty->getContext(), RandomFloat));
+ }
+
+ if (Ty->isIntegerTy()) {
+ switch (Ran->Rand() % 7) {
+ case 0: if (Ty->isIntegerTy())
+ return PT->push_back(ConstantInt::get(Ty,
+ APInt::getAllOnesValue(Ty->getPrimitiveSizeInBits())));
+ case 1: if (Ty->isIntegerTy())
+ return PT->push_back(ConstantInt::get(Ty,
+ APInt::getNullValue(Ty->getPrimitiveSizeInBits())));
+ case 2: case 3: case 4: case 5:
+ case 6: if (Ty->isIntegerTy())
+ PT->push_back(ConstantInt::get(Ty, Ran->Rand()));
+ }
+ }
+
+ }
+};
+
+struct AllocaModifier: public Modifier {
+ AllocaModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R){}
+
+ virtual void Act() {
+ Type *Tp = pickType();
+ PT->push_back(new AllocaInst(Tp, "A", BB->getFirstNonPHI()));
+ }
+};
+
+struct ExtractElementModifier: public Modifier {
+ ExtractElementModifier(BasicBlock *BB, PieceTable *PT, Random *R):
+ Modifier(BB, PT, R) {}
+
+ virtual void Act() {
+ Value *Val0 = getRandomVectorValue();
+ Value *V = ExtractElementInst::Create(Val0,
+ ConstantInt::get(Type::getInt32Ty(BB->getContext()),
+ Ran->Rand() % cast<VectorType>(Val0->getType())->getNumElements()),
+ "E", BB->getTerminator());
+ return PT->push_back(V);
+ }
+};
+
+struct ShuffModifier: public Modifier {
+ ShuffModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {}
+ virtual void Act() {
+
+ Value *Val0 = getRandomVectorValue();
+ Value *Val1 = getRandomValue(Val0->getType());
+
+ unsigned Width = cast<VectorType>(Val0->getType())->getNumElements();
+ std::vector<Constant*> Idxs;
+
+ Type *I32 = Type::getInt32Ty(BB->getContext());
+ for (unsigned i=0; i<Width; ++i) {
+ Constant *CI = ConstantInt::get(I32, Ran->Rand() % (Width*2));
+ // Pick some undef values.
+ if (!(Ran->Rand() % 5))
+ CI = UndefValue::get(I32);
+ Idxs.push_back(CI);
+ }
+
+ Constant *Mask = ConstantVector::get(Idxs);
+
+ Value *V = new ShuffleVectorInst(Val0, Val1, Mask, "Shuff",
+ BB->getTerminator());
+ PT->push_back(V);
+ }
+};
+
+struct InsertElementModifier: public Modifier {
+ InsertElementModifier(BasicBlock *BB, PieceTable *PT, Random *R):
+ Modifier(BB, PT, R) {}
+
+ virtual void Act() {
+ Value *Val0 = getRandomVectorValue();
+ Value *Val1 = getRandomValue(Val0->getType()->getScalarType());
+
+ Value *V = InsertElementInst::Create(Val0, Val1,
+ ConstantInt::get(Type::getInt32Ty(BB->getContext()),
+ Ran->Rand() % cast<VectorType>(Val0->getType())->getNumElements()),
+ "I", BB->getTerminator());
+ return PT->push_back(V);
+ }
+
+};
+
+struct CastModifier: public Modifier {
+ CastModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {}
+ virtual void Act() {
+
+ Value *V = getRandomVal();
+ Type *VTy = V->getType();
+ Type *DestTy = pickScalarType();
+
+ // Handle vector casts vectors.
+ if (VTy->isVectorTy()) {
+ VectorType *VecTy = cast<VectorType>(VTy);
+ DestTy = pickVectorType(VecTy->getNumElements());
+ }
+
+ // no need to casr.
+ if (VTy == DestTy) return;
+
+ // Pointers:
+ if (VTy->isPointerTy()) {
+ if (!DestTy->isPointerTy())
+ DestTy = PointerType::get(DestTy, 0);
+ return PT->push_back(
+ new BitCastInst(V, DestTy, "PC", BB->getTerminator()));
+ }
+
+ // Generate lots of bitcasts.
+ if ((Ran->Rand() & 1) &&
+ VTy->getPrimitiveSizeInBits() == DestTy->getPrimitiveSizeInBits()) {
+ return PT->push_back(
+ new BitCastInst(V, DestTy, "BC", BB->getTerminator()));
+ }
+
+ // Both types are integers:
+ if (VTy->getScalarType()->isIntegerTy() &&
+ DestTy->getScalarType()->isIntegerTy()) {
+ if (VTy->getScalarType()->getPrimitiveSizeInBits() >
+ DestTy->getScalarType()->getPrimitiveSizeInBits()) {
+ return PT->push_back(
+ new TruncInst(V, DestTy, "Tr", BB->getTerminator()));
+ } else {
+ if (Ran->Rand() & 1)
+ return PT->push_back(
+ new ZExtInst(V, DestTy, "ZE", BB->getTerminator()));
+ return PT->push_back(new SExtInst(V, DestTy, "Se", BB->getTerminator()));
+ }
+ }
+
+ // Fp to int.
+ if (VTy->getScalarType()->isFloatingPointTy() &&
+ DestTy->getScalarType()->isIntegerTy()) {
+ if (Ran->Rand() & 1)
+ return PT->push_back(
+ new FPToSIInst(V, DestTy, "FC", BB->getTerminator()));
+ return PT->push_back(new FPToUIInst(V, DestTy, "FC", BB->getTerminator()));
+ }
+
+ // Int to fp.
+ if (VTy->getScalarType()->isIntegerTy() &&
+ DestTy->getScalarType()->isFloatingPointTy()) {
+ if (Ran->Rand() & 1)
+ return PT->push_back(
+ new SIToFPInst(V, DestTy, "FC", BB->getTerminator()));
+ return PT->push_back(new UIToFPInst(V, DestTy, "FC", BB->getTerminator()));
+
+ }
+
+ // Both floats.
+ if (VTy->getScalarType()->isFloatingPointTy() &&
+ DestTy->getScalarType()->isFloatingPointTy()) {
+ if (VTy->getScalarType()->getPrimitiveSizeInBits() >
+ DestTy->getScalarType()->getPrimitiveSizeInBits()) {
+ return PT->push_back(
+ new FPTruncInst(V, DestTy, "Tr", BB->getTerminator()));
+ } else {
+ return PT->push_back(
+ new FPExtInst(V, DestTy, "ZE", BB->getTerminator()));
+ }
+ }
+ }
+
+};
+
+struct SelectModifier: public Modifier {
+ SelectModifier(BasicBlock *BB, PieceTable *PT, Random *R):
+ Modifier(BB, PT, R) {}
+
+ virtual void Act() {
+ // Try a bunch of different select configuration until a valid one is found.
+ Value *Val0 = getRandomVal();
+ Value *Val1 = getRandomValue(Val0->getType());
+
+ Type *CondTy = Type::getInt1Ty(Context);
+
+ // If the value type is a vector, and we allow vector select, then in 50%
+ // of the cases generate a vector select.
+ if (Val0->getType()->isVectorTy() && (Ran->Rand() % 1)) {
+ unsigned NumElem = cast<VectorType>(Val0->getType())->getNumElements();
+ CondTy = VectorType::get(CondTy, NumElem);
+ }
+
+ Value *Cond = getRandomValue(CondTy);
+ Value *V = SelectInst::Create(Cond, Val0, Val1, "Sl", BB->getTerminator());
+ return PT->push_back(V);
+ }
+};
+
+
+struct CmpModifier: public Modifier {
+ CmpModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {}
+ virtual void Act() {
+
+ Value *Val0 = getRandomVal();
+ Value *Val1 = getRandomValue(Val0->getType());
+
+ if (Val0->getType()->isPointerTy()) return;
+ bool fp = Val0->getType()->getScalarType()->isFloatingPointTy();
+
+ int op;
+ if (fp) {
+ op = Ran->Rand() %
+ (CmpInst::LAST_FCMP_PREDICATE - CmpInst::FIRST_FCMP_PREDICATE) +
+ CmpInst::FIRST_FCMP_PREDICATE;
+ } else {
+ op = Ran->Rand() %
+ (CmpInst::LAST_ICMP_PREDICATE - CmpInst::FIRST_ICMP_PREDICATE) +
+ CmpInst::FIRST_ICMP_PREDICATE;
+ }
+
+ Value *V = CmpInst::Create(fp ? Instruction::FCmp : Instruction::ICmp,
+ op, Val0, Val1, "Cmp", BB->getTerminator());
+ return PT->push_back(V);
+ }
+};
+
+void FillFunction(Function *F) {
+ // Create a legal entry block.
+ BasicBlock *BB = BasicBlock::Create(F->getContext(), "BB", F);
+ ReturnInst::Create(F->getContext(), BB);
+
+ // Create the value table.
+ Modifier::PieceTable PT;
+ // Pick an initial seed value
+ Random R(SeedCL);
+
+ // Consider arguments as legal values.
+ for (Function::arg_iterator it = F->arg_begin(), e = F->arg_end();
+ it != e; ++it)
+ PT.push_back(it);
+
+ // List of modifiers which add new random instructions.
+ std::vector<Modifier*> Modifiers;
+ std::auto_ptr<Modifier> LM(new LoadModifier(BB, &PT, &R));
+ std::auto_ptr<Modifier> SM(new StoreModifier(BB, &PT, &R));
+ std::auto_ptr<Modifier> EE(new ExtractElementModifier(BB, &PT, &R));
+ std::auto_ptr<Modifier> SHM(new ShuffModifier(BB, &PT, &R));
+ std::auto_ptr<Modifier> IE(new InsertElementModifier(BB, &PT, &R));
+ std::auto_ptr<Modifier> BM(new BinModifier(BB, &PT, &R));
+ std::auto_ptr<Modifier> CM(new CastModifier(BB, &PT, &R));
+ std::auto_ptr<Modifier> SLM(new SelectModifier(BB, &PT, &R));
+ std::auto_ptr<Modifier> PM(new CmpModifier(BB, &PT, &R));
+ Modifiers.push_back(LM.get());
+ Modifiers.push_back(SM.get());
+ Modifiers.push_back(EE.get());
+ Modifiers.push_back(SHM.get());
+ Modifiers.push_back(IE.get());
+ Modifiers.push_back(BM.get());
+ Modifiers.push_back(CM.get());
+ Modifiers.push_back(SLM.get());
+ Modifiers.push_back(PM.get());
+
+ // Generate the random instructions
+ AllocaModifier AM(BB, &PT, &R); AM.ActN(5); // Throw in a few allocas
+ ConstModifier COM(BB, &PT, &R); COM.ActN(40); // Throw in a few constants
+
+ for (unsigned i=0; i< SizeCL / Modifiers.size(); ++i)
+ for (std::vector<Modifier*>::iterator it = Modifiers.begin(),
+ e = Modifiers.end(); it != e; ++it) {
+ (*it)->Act();
+ }
+
+ SM->ActN(5); // Throw in a few stores.
+}
+
+void IntroduceControlFlow(Function *F) {
+ std::set<Instruction*> BoolInst;
+ for (BasicBlock::iterator it = F->begin()->begin(),
+ e = F->begin()->end(); it != e; ++it) {
+ if (it->getType() == IntegerType::getInt1Ty(F->getContext()))
+ BoolInst.insert(it);
+ }
+
+ for (std::set<Instruction*>::iterator it = BoolInst.begin(),
+ e = BoolInst.end(); it != e; ++it) {
+ Instruction *Instr = *it;
+ BasicBlock *Curr = Instr->getParent();
+ BasicBlock::iterator Loc= Instr;
+ BasicBlock *Next = Curr->splitBasicBlock(Loc, "CF");
+ Instr->moveBefore(Curr->getTerminator());
+ if (Curr != &F->getEntryBlock()) {
+ BranchInst::Create(Curr, Next, Instr, Curr->getTerminator());
+ Curr->getTerminator()->eraseFromParent();
+ }
+ }
+}
+
+int main(int argc, char **argv) {
+ // Init LLVM, call llvm_shutdown() on exit, parse args, etc.
+ llvm::PrettyStackTraceProgram X(argc, argv);
+ cl::ParseCommandLineOptions(argc, argv, "llvm codegen stress-tester\n");
+ llvm_shutdown_obj Y;
+
+ std::auto_ptr<Module> M(new Module("/tmp/autogen.bc", getGlobalContext()));
+ Function *F = GenEmptyFunction(M.get());
+ FillFunction(F);
+ IntroduceControlFlow(F);
+
+ // Figure out what stream we are supposed to write to...
+ OwningPtr<tool_output_file> Out;
+ // Default to standard output.
+ if (OutputFilename.empty())
+ OutputFilename = "-";
+
+ std::string ErrorInfo;
+ Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo,
+ raw_fd_ostream::F_Binary));
+ if (!ErrorInfo.empty()) {
+ errs() << ErrorInfo << '\n';
+ return 1;
+ }
+
+ PassManager Passes;
+ Passes.add(createVerifierPass());
+ Passes.add(createPrintModulePass(&Out->os()));
+ Passes.run(*M.get());
+ Out->keep();
+
+ return 0;
+}
diff --git a/contrib/llvm/tools/llvm-stub/CMakeLists.txt b/contrib/llvm/tools/llvm-stub/CMakeLists.txt
deleted file mode 100644
index a98dc9e..0000000
--- a/contrib/llvm/tools/llvm-stub/CMakeLists.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-add_llvm_tool(llvm-stub
- llvm-stub.c
- )
diff --git a/contrib/llvm/tools/llvm-stub/Makefile b/contrib/llvm/tools/llvm-stub/Makefile
deleted file mode 100644
index 7ffe149..0000000
--- a/contrib/llvm/tools/llvm-stub/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-##===- tools/llvm-stub/Makefile ----------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = llvm-stub
-include $(LEVEL)/Makefile.common
-
diff --git a/contrib/llvm/tools/macho-dump/CMakeLists.txt b/contrib/llvm/tools/macho-dump/CMakeLists.txt
deleted file mode 100644
index d55e1d5..0000000
--- a/contrib/llvm/tools/macho-dump/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support object)
-
-add_llvm_tool(macho-dump
- macho-dump.cpp
- )
diff --git a/contrib/llvm/tools/macho-dump/Makefile b/contrib/llvm/tools/macho-dump/Makefile
deleted file mode 100644
index 638015e..0000000
--- a/contrib/llvm/tools/macho-dump/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-##===- tools/macho-dump/Makefile ---------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-
-LEVEL = ../..
-TOOLNAME = macho-dump
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS = 1
-
-# Include this here so we can get the configuration of the targets
-# that have been configured for construction. We have to do this
-# early so we can set up LINK_COMPONENTS before including Makefile.rules
-include $(LEVEL)/Makefile.config
-
-LINK_COMPONENTS := support object
-
-include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/contrib/llvm/tools/opt/CMakeLists.txt b/contrib/llvm/tools/opt/CMakeLists.txt
deleted file mode 100644
index 0570d0e..0000000
--- a/contrib/llvm/tools/opt/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-set(LLVM_LINK_COMPONENTS bitreader asmparser bitwriter instrumentation scalaropts ipo)
-
-add_llvm_tool(opt
- AnalysisWrappers.cpp
- GraphPrinters.cpp
- PrintSCC.cpp
- opt.cpp
- )
diff --git a/contrib/llvm/tools/opt/Makefile b/contrib/llvm/tools/opt/Makefile
deleted file mode 100644
index 726cad8..0000000
--- a/contrib/llvm/tools/opt/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-##===- tools/opt/Makefile ----------------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-LEVEL = ../..
-TOOLNAME = opt
-
-LINK_COMPONENTS := bitreader bitwriter asmparser instrumentation scalaropts ipo
-
-include $(LEVEL)/Makefile.common
diff --git a/contrib/llvm/tools/opt/PrintSCC.cpp b/contrib/llvm/tools/opt/PrintSCC.cpp
index 533f49e..11efdcd 100644
--- a/contrib/llvm/tools/opt/PrintSCC.cpp
+++ b/contrib/llvm/tools/opt/PrintSCC.cpp
@@ -101,8 +101,8 @@ bool CallGraphSCC::runOnModule(Module &M) {
errs() << "\nSCC #" << ++sccNum << " : ";
for (std::vector<CallGraphNode*>::const_iterator I = nextSCC.begin(),
E = nextSCC.end(); I != E; ++I)
- errs() << ((*I)->getFunction() ? (*I)->getFunction()->getNameStr()
- : std::string("external node")) << ", ";
+ errs() << ((*I)->getFunction() ? (*I)->getFunction()->getName()
+ : "external node") << ", ";
if (nextSCC.size() == 1 && SCCI.hasLoop())
errs() << " (Has self-loop).";
}
diff --git a/contrib/llvm/tools/opt/opt.cpp b/contrib/llvm/tools/opt/opt.cpp
index ffd2c21..30da863 100644
--- a/contrib/llvm/tools/opt/opt.cpp
+++ b/contrib/llvm/tools/opt/opt.cpp
@@ -291,8 +291,8 @@ struct RegionPassPrinter : public RegionPass {
virtual bool runOnRegion(Region *R, RGPassManager &RGM) {
if (!Quiet) {
Out << "Printing analysis '" << PassToPrint->getPassName() << "' for "
- << "region: '" << R->getNameStr() << "' in function '"
- << R->getEntry()->getParent()->getNameStr() << "':\n";
+ << "region: '" << R->getNameStr() << "' in function '"
+ << R->getEntry()->getParent()->getName() << "':\n";
}
// Get and print pass...
getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out,
@@ -407,6 +407,8 @@ static inline void addPass(PassManagerBase &PM, Pass *P) {
/// OptLevel - Optimization Level
static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM,
unsigned OptLevel) {
+ FPM.add(createVerifierPass()); // Verify that input is correct
+
PassManagerBuilder Builder;
Builder.OptLevel = OptLevel;
@@ -478,6 +480,7 @@ int main(int argc, char **argv) {
PassRegistry &Registry = *PassRegistry::getPassRegistry();
initializeCore(Registry);
initializeScalarOpts(Registry);
+ initializeVectorization(Registry);
initializeIPO(Registry);
initializeAnalysis(Registry);
initializeIPA(Registry);
@@ -505,7 +508,7 @@ int main(int argc, char **argv) {
M.reset(ParseIRFile(InputFilename, Err, Context));
if (M.get() == 0) {
- Err.Print(argv[0], errs());
+ Err.print(argv[0], errs());
return 1;
}
OpenPOWER on IntegriCloud