aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-10-23 17:52:09 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-10-23 17:52:09 +0000
commit519fc96c475680de2cc49e7811dbbfadb912cbcc (patch)
tree310ca684459b7e9ae13c9a3b9abf308b3a634afe
parent2298981669bf3bd63335a4be179bc0f96823a8f4 (diff)
downloadsrc-vendor/clang.tar.gz
src-vendor/clang.zip
Vendor import of stripped clang trunk r375505, the last commit beforevendor/clang/clang-trunk-r375505vendor/clang
the upstream Subversion repository was made read-only, and the LLVM project migrated to GitHub: https://llvm.org/svn/llvm-project/cfe/trunk@375505
Notes
Notes: svn path=/vendor/clang/dist/; revision=353942 svn path=/vendor/clang/clang-r375505/; revision=353943; tag=vendor/clang/clang-trunk-r375505
-rw-r--r--include/clang-c/FatalErrorHandler.h33
-rw-r--r--include/clang-c/Index.h22
-rw-r--r--include/clang/AST/APValue.h46
-rw-r--r--include/clang/AST/ASTContext.h136
-rw-r--r--include/clang/AST/ASTFwd.h2
-rw-r--r--include/clang/AST/ASTImporter.h43
-rw-r--r--include/clang/AST/ASTImporterSharedState.h2
-rw-r--r--include/clang/AST/ASTNodeTraverser.h3
-rw-r--r--include/clang/AST/ASTStructuralEquivalence.h19
-rw-r--r--include/clang/AST/ASTTypeTraits.h4
-rw-r--r--include/clang/AST/Attr.h151
-rw-r--r--include/clang/AST/CXXRecordDeclDefinitionBits.def236
-rw-r--r--include/clang/AST/CharUnits.h5
-rw-r--r--include/clang/AST/CommentCommands.td1
-rw-r--r--include/clang/AST/CommentLexer.h3
-rw-r--r--include/clang/AST/Decl.h52
-rw-r--r--include/clang/AST/DeclBase.h2
-rw-r--r--include/clang/AST/DeclCXX.h343
-rw-r--r--include/clang/AST/DeclTemplate.h178
-rw-r--r--include/clang/AST/Expr.h16
-rw-r--r--include/clang/AST/ExprCXX.h235
-rw-r--r--include/clang/AST/ExternalASTMerger.h38
-rw-r--r--include/clang/AST/FormatString.h22
-rw-r--r--include/clang/AST/GlobalDecl.h1
-rw-r--r--include/clang/AST/JSONNodeDumper.h2
-rw-r--r--include/clang/AST/Mangle.h18
-rw-r--r--include/clang/AST/NSAPI.h3
-rw-r--r--include/clang/AST/OpenMPClause.h157
-rw-r--r--include/clang/AST/OperationKinds.def5
-rw-r--r--include/clang/AST/OptionalDiagnostic.h78
-rw-r--r--include/clang/AST/RawCommentList.h23
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h100
-rw-r--r--include/clang/AST/Stmt.h10
-rw-r--r--include/clang/AST/StmtOpenMP.h302
-rw-r--r--include/clang/AST/TextNodeDumper.h2
-rw-r--r--include/clang/AST/Type.h105
-rw-r--r--include/clang/AST/TypeLoc.h2
-rw-r--r--include/clang/AST/TypeLocNodes.def2
-rw-r--r--include/clang/AST/TypeNodes.def135
-rw-r--r--include/clang/AST/TypeVisitor.h4
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h186
-rw-r--r--include/clang/ASTMatchers/ASTMatchersInternal.h25
-rw-r--r--include/clang/Analysis/AnalysisDeclContext.h51
-rw-r--r--include/clang/Analysis/CFG.h195
-rw-r--r--include/clang/Analysis/CallGraph.h1
-rw-r--r--include/clang/Analysis/PathDiagnostic.h (renamed from include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h)145
-rw-r--r--include/clang/Basic/AArch64SVEACLETypes.def70
-rw-r--r--include/clang/Basic/Attr.td182
-rw-r--r--include/clang/Basic/AttrDocs.td210
-rw-r--r--include/clang/Basic/AttributeCommonInfo.h190
-rw-r--r--include/clang/Basic/Builtins.def27
-rw-r--r--include/clang/Basic/BuiltinsAArch64.def56
-rw-r--r--include/clang/Basic/BuiltinsAMDGPU.def9
-rw-r--r--include/clang/Basic/BuiltinsARM.def48
-rw-r--r--include/clang/Basic/BuiltinsBPF.def24
-rw-r--r--include/clang/Basic/BuiltinsPPC.def14
-rw-r--r--include/clang/Basic/BuiltinsWebAssembly.def33
-rw-r--r--include/clang/Basic/BuiltinsX86.def4
-rw-r--r--include/clang/Basic/BuiltinsX86_64.def4
-rw-r--r--include/clang/Basic/CodeGenOptions.def14
-rw-r--r--include/clang/Basic/CodeGenOptions.h6
-rw-r--r--include/clang/Basic/Diagnostic.h17
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td139
-rw-r--r--include/clang/Basic/DiagnosticCommentKinds.td6
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td26
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td9
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td13
-rw-r--r--include/clang/Basic/DiagnosticGroups.td50
-rw-r--r--include/clang/Basic/DiagnosticOptions.def1
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td55
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td388
-rw-r--r--include/clang/Basic/DiagnosticSerializationKinds.td15
-rw-r--r--include/clang/Basic/Features.def4
-rw-r--r--include/clang/Basic/FileManager.h204
-rw-r--r--include/clang/Basic/IdentifierTable.h6
-rw-r--r--include/clang/Basic/LangOptions.def11
-rw-r--r--include/clang/Basic/LangOptions.h16
-rw-r--r--include/clang/Basic/LangStandard.h (renamed from include/clang/Frontend/LangStandard.h)69
-rw-r--r--include/clang/Basic/LangStandards.def (renamed from include/clang/Frontend/LangStandards.def)5
-rw-r--r--include/clang/Basic/Linkage.h6
-rw-r--r--include/clang/Basic/OpenCLOptions.h6
-rw-r--r--include/clang/Basic/OpenMPKinds.def103
-rw-r--r--include/clang/Basic/OpenMPKinds.h13
-rw-r--r--include/clang/Basic/OperatorKinds.h19
-rw-r--r--include/clang/Basic/SourceManager.h83
-rw-r--r--include/clang/Basic/Specifiers.h3
-rw-r--r--include/clang/Basic/Stack.h29
-rw-r--r--include/clang/Basic/StmtNodes.td7
-rw-r--r--include/clang/Basic/SyncScope.h2
-rw-r--r--include/clang/Basic/TargetBuiltins.h10
-rw-r--r--include/clang/Basic/TargetInfo.h23
-rw-r--r--include/clang/Basic/TokenKinds.def72
-rw-r--r--include/clang/Basic/TokenKinds.h11
-rw-r--r--include/clang/Basic/TypeNodes.td106
-rw-r--r--include/clang/Basic/X86Target.def5
-rw-r--r--include/clang/Basic/arm_neon.td8
-rw-r--r--include/clang/CodeGen/CGFunctionInfo.h10
-rw-r--r--include/clang/CrossTU/CrossTranslationUnit.h143
-rw-r--r--include/clang/DirectoryWatcher/DirectoryWatcher.h10
-rw-r--r--include/clang/Driver/Action.h26
-rw-r--r--include/clang/Driver/CC1Options.td16
-rw-r--r--include/clang/Driver/CLCompatOptions.td14
-rw-r--r--include/clang/Driver/Driver.h14
-rw-r--r--include/clang/Driver/Options.h2
-rw-r--r--include/clang/Driver/Options.td136
-rw-r--r--include/clang/Driver/Phases.h3
-rw-r--r--include/clang/Driver/SanitizerArgs.h7
-rw-r--r--include/clang/Driver/ToolChain.h9
-rw-r--r--include/clang/Driver/Types.def123
-rw-r--r--include/clang/Driver/Types.h7
-rw-r--r--include/clang/Format/Format.h240
-rw-r--r--include/clang/Frontend/ASTUnit.h5
-rw-r--r--include/clang/Frontend/CompilerInstance.h24
-rw-r--r--include/clang/Frontend/CompilerInvocation.h14
-rw-r--r--include/clang/Frontend/FrontendActions.h9
-rw-r--r--include/clang/Frontend/FrontendOptions.h51
-rw-r--r--include/clang/Frontend/Utils.h13
-rw-r--r--include/clang/Index/CodegenNameGenerator.h52
-rw-r--r--include/clang/Index/IndexDataConsumer.h16
-rw-r--r--include/clang/Index/IndexingAction.h37
-rw-r--r--include/clang/Index/IndexingOptions.h42
-rw-r--r--include/clang/Lex/DependencyDirectivesSourceMinimizer.h22
-rw-r--r--include/clang/Lex/DirectoryLookup.h68
-rw-r--r--include/clang/Lex/HeaderMap.h5
-rw-r--r--include/clang/Lex/HeaderSearch.h14
-rw-r--r--include/clang/Lex/HeaderSearchOptions.h27
-rw-r--r--include/clang/Lex/Lexer.h15
-rw-r--r--include/clang/Lex/MacroArgs.h10
-rw-r--r--include/clang/Lex/PPCallbacks.h12
-rw-r--r--include/clang/Lex/Preprocessor.h55
-rw-r--r--include/clang/Lex/PreprocessorExcludedConditionalDirectiveSkipMapping.h31
-rw-r--r--include/clang/Lex/PreprocessorOptions.h16
-rw-r--r--include/clang/Parse/Parser.h50
-rw-r--r--include/clang/Rewrite/Core/Rewriter.h11
-rw-r--r--include/clang/Sema/Overload.h102
-rw-r--r--include/clang/Sema/ParsedAttr.h212
-rw-r--r--include/clang/Sema/ScopeInfo.h10
-rw-r--r--include/clang/Sema/Sema.h577
-rw-r--r--include/clang/Sema/SemaInternal.h2
-rw-r--r--include/clang/Sema/TypoCorrection.h8
-rw-r--r--include/clang/Serialization/ASTBitCodes.h17
-rw-r--r--include/clang/Serialization/ASTReader.h14
-rw-r--r--include/clang/StaticAnalyzer/Checkers/Checkers.td43
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.def32
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.h68
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h656
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h217
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugType.h40
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h1
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h24
-rw-r--r--include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h12
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h9
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h27
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h17
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/DynamicCastInfo.h55
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h73
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h46
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h63
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h54
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h6
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h4
-rw-r--r--include/clang/Tooling/ASTDiff/ASTDiff.h2
-rw-r--r--include/clang/Tooling/AllTUsExecution.h3
-rw-r--r--include/clang/Tooling/ArgumentsAdjusters.h4
-rw-r--r--include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h188
-rw-r--r--include/clang/Tooling/DependencyScanning/DependencyScanningService.h65
-rw-r--r--include/clang/Tooling/DependencyScanning/DependencyScanningTool.h48
-rw-r--r--include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h42
-rw-r--r--include/clang/Tooling/Execution.h7
-rw-r--r--include/clang/Tooling/Inclusions/HeaderIncludes.h1
-rw-r--r--include/clang/Tooling/Inclusions/IncludeStyle.h2
-rwxr-xr-x[-rw-r--r--]include/clang/Tooling/Refactoring/Extract/SourceExtraction.h (renamed from lib/Tooling/Refactoring/Extract/SourceExtraction.h)6
-rw-r--r--include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h15
-rw-r--r--include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h10
-rw-r--r--include/clang/Tooling/StandaloneExecution.h2
-rw-r--r--include/clang/Tooling/Syntax/Tokens.h10
-rw-r--r--include/clang/Tooling/Tooling.h30
-rw-r--r--include/clang/Tooling/Transformer/MatchConsumer.h62
-rw-r--r--include/clang/Tooling/Transformer/RangeSelector.h (renamed from include/clang/Tooling/Refactoring/RangeSelector.h)30
-rw-r--r--include/clang/Tooling/Transformer/RewriteRule.h (renamed from include/clang/Tooling/Refactoring/Transformer.h)109
-rw-r--r--include/clang/Tooling/Transformer/SourceCode.h (renamed from include/clang/Tooling/Refactoring/SourceCode.h)19
-rw-r--r--include/clang/Tooling/Transformer/SourceCodeBuilders.h86
-rw-r--r--include/clang/Tooling/Transformer/Stencil.h (renamed from include/clang/Tooling/Refactoring/Stencil.h)130
-rw-r--r--include/clang/Tooling/Transformer/Transformer.h52
-rw-r--r--include/clang/module.modulemap6
-rw-r--r--lib/ARCMigrate/ARCMT.cpp6
-rw-r--r--lib/ARCMigrate/FileRemapper.cpp24
-rw-r--r--lib/ARCMigrate/ObjCMT.cpp15
-rw-r--r--lib/ARCMigrate/PlistReporter.cpp2
-rw-r--r--lib/AST/APValue.cpp38
-rw-r--r--lib/AST/ASTContext.cpp757
-rw-r--r--lib/AST/ASTDiagnostic.cpp2
-rw-r--r--lib/AST/ASTImporter.cpp542
-rw-r--r--lib/AST/ASTStructuralEquivalence.cpp90
-rw-r--r--lib/AST/ASTTypeTraits.cpp16
-rw-r--r--lib/AST/CXXInheritance.cpp2
-rw-r--r--lib/AST/Comment.cpp15
-rw-r--r--lib/AST/CommentLexer.cpp7
-rw-r--r--lib/AST/CommentParser.cpp6
-rw-r--r--lib/AST/CommentSema.cpp8
-rw-r--r--lib/AST/Decl.cpp75
-rw-r--r--lib/AST/DeclBase.cpp15
-rw-r--r--lib/AST/DeclCXX.cpp84
-rw-r--r--lib/AST/DeclPrinter.cpp15
-rw-r--r--lib/AST/DeclTemplate.cpp69
-rw-r--r--lib/AST/Expr.cpp140
-rw-r--r--lib/AST/ExprCXX.cpp176
-rw-r--r--lib/AST/ExprClassification.cpp5
-rw-r--r--lib/AST/ExprConstant.cpp2474
-rw-r--r--lib/AST/ExternalASTMerger.cpp124
-rw-r--r--lib/AST/FormatString.cpp4
-rw-r--r--lib/AST/FormatStringParsing.h13
-rw-r--r--lib/AST/InheritViz.cpp4
-rw-r--r--lib/AST/Interp/Block.cpp87
-rw-r--r--lib/AST/Interp/Block.h140
-rw-r--r--lib/AST/Interp/Boolean.h148
-rw-r--r--lib/AST/Interp/ByteCodeEmitter.cpp175
-rw-r--r--lib/AST/Interp/ByteCodeEmitter.h112
-rw-r--r--lib/AST/Interp/ByteCodeExprGen.cpp580
-rw-r--r--lib/AST/Interp/ByteCodeExprGen.h331
-rw-r--r--lib/AST/Interp/ByteCodeGenError.cpp14
-rw-r--r--lib/AST/Interp/ByteCodeGenError.h46
-rw-r--r--lib/AST/Interp/ByteCodeStmtGen.cpp265
-rw-r--r--lib/AST/Interp/ByteCodeStmtGen.h89
-rw-r--r--lib/AST/Interp/Context.cpp148
-rw-r--r--lib/AST/Interp/Context.h100
-rw-r--r--lib/AST/Interp/Descriptor.cpp292
-rw-r--r--lib/AST/Interp/Descriptor.h220
-rw-r--r--lib/AST/Interp/Disasm.cpp69
-rw-r--r--lib/AST/Interp/EvalEmitter.cpp253
-rw-r--r--lib/AST/Interp/EvalEmitter.h129
-rw-r--r--lib/AST/Interp/Frame.cpp14
-rw-r--r--lib/AST/Interp/Frame.h45
-rw-r--r--lib/AST/Interp/Function.cpp48
-rw-r--r--lib/AST/Interp/Function.h163
-rw-r--r--lib/AST/Interp/Integral.h269
-rw-r--r--lib/AST/Interp/Interp.cpp417
-rw-r--r--lib/AST/Interp/Interp.h960
-rw-r--r--lib/AST/Interp/InterpFrame.cpp193
-rw-r--r--lib/AST/Interp/InterpFrame.h153
-rw-r--r--lib/AST/Interp/InterpStack.cpp78
-rw-r--r--lib/AST/Interp/InterpStack.h113
-rw-r--r--lib/AST/Interp/InterpState.cpp74
-rw-r--r--lib/AST/Interp/InterpState.h112
-rw-r--r--lib/AST/Interp/Opcode.h30
-rw-r--r--lib/AST/Interp/Opcodes.td422
-rw-r--r--lib/AST/Interp/Pointer.cpp193
-rw-r--r--lib/AST/Interp/Pointer.h353
-rw-r--r--lib/AST/Interp/PrimType.cpp23
-rw-r--r--lib/AST/Interp/PrimType.h115
-rw-r--r--lib/AST/Interp/Program.cpp364
-rw-r--r--lib/AST/Interp/Program.h220
-rw-r--r--lib/AST/Interp/Record.cpp46
-rw-r--r--lib/AST/Interp/Record.h121
-rw-r--r--lib/AST/Interp/Source.cpp39
-rw-r--r--lib/AST/Interp/Source.h118
-rw-r--r--lib/AST/Interp/State.cpp158
-rw-r--r--lib/AST/Interp/State.h133
-rw-r--r--lib/AST/ItaniumCXXABI.cpp72
-rw-r--r--lib/AST/ItaniumMangle.cpp154
-rw-r--r--lib/AST/JSONNodeDumper.cpp49
-rw-r--r--lib/AST/Mangle.cpp16
-rw-r--r--lib/AST/MicrosoftCXXABI.cpp4
-rw-r--r--lib/AST/MicrosoftMangle.cpp32
-rw-r--r--lib/AST/NSAPI.cpp14
-rw-r--r--lib/AST/OpenMPClause.cpp71
-rw-r--r--lib/AST/PrintfFormatString.cpp20
-rw-r--r--lib/AST/RawCommentList.cpp64
-rw-r--r--lib/AST/Stmt.cpp11
-rw-r--r--lib/AST/StmtOpenMP.cpp246
-rw-r--r--lib/AST/StmtPrinter.cpp46
-rw-r--r--lib/AST/StmtProfile.cpp37
-rw-r--r--lib/AST/TemplateBase.cpp2
-rw-r--r--lib/AST/TextNodeDumper.cpp17
-rw-r--r--lib/AST/Type.cpp113
-rw-r--r--lib/AST/TypeLoc.cpp3
-rw-r--r--lib/AST/TypePrinter.cpp11
-rw-r--r--lib/AST/VTTBuilder.cpp12
-rw-r--r--lib/AST/VTableBuilder.cpp12
-rw-r--r--lib/ASTMatchers/ASTMatchFinder.cpp73
-rw-r--r--lib/ASTMatchers/Dynamic/Marshallers.h14
-rw-r--r--lib/ASTMatchers/Dynamic/Registry.cpp3
-rw-r--r--lib/Analysis/AnalysisDeclContext.cpp23
-rw-r--r--lib/Analysis/BodyFarm.cpp4
-rw-r--r--lib/Analysis/CFG.cpp432
-rw-r--r--lib/Analysis/CallGraph.cpp42
-rw-r--r--lib/Analysis/CloneDetection.cpp3
-rw-r--r--lib/Analysis/CocoaConventions.cpp4
-rw-r--r--lib/Analysis/Consumed.cpp12
-rw-r--r--lib/Analysis/PathDiagnostic.cpp (renamed from lib/StaticAnalyzer/Core/PathDiagnostic.cpp)289
-rw-r--r--lib/Analysis/ProgramPoint.cpp6
-rw-r--r--lib/Analysis/ReachableCode.cpp2
-rw-r--r--lib/Analysis/RetainSummaryManager.cpp2
-rw-r--r--lib/Analysis/ThreadSafety.cpp30
-rw-r--r--lib/Analysis/plugins/SampleAnalyzer/MainCallChecker.cpp4
-rw-r--r--lib/Basic/Attributes.cpp75
-rw-r--r--lib/Basic/FileManager.cpp257
-rw-r--r--lib/Basic/IdentifierTable.cpp15
-rw-r--r--lib/Basic/LangStandards.cpp (renamed from lib/Frontend/LangStandards.cpp)25
-rw-r--r--lib/Basic/Module.cpp4
-rw-r--r--lib/Basic/OpenMPKinds.cpp85
-rw-r--r--lib/Basic/SourceManager.cpp203
-rw-r--r--lib/Basic/Stack.cpp75
-rw-r--r--lib/Basic/TargetInfo.cpp6
-rw-r--r--lib/Basic/Targets.cpp23
-rw-r--r--lib/Basic/Targets/AArch64.cpp32
-rw-r--r--lib/Basic/Targets/AArch64.h1
-rw-r--r--lib/Basic/Targets/AMDGPU.cpp8
-rw-r--r--lib/Basic/Targets/ARM.cpp103
-rw-r--r--lib/Basic/Targets/BPF.cpp12
-rw-r--r--lib/Basic/Targets/BPF.h4
-rw-r--r--lib/Basic/Targets/OSTargets.h15
-rw-r--r--lib/Basic/Targets/PPC.cpp10
-rw-r--r--lib/Basic/Targets/PPC.h1
-rw-r--r--lib/Basic/Targets/RISCV.cpp63
-rw-r--r--lib/Basic/Targets/RISCV.h20
-rw-r--r--lib/Basic/Targets/SPIR.h2
-rw-r--r--lib/Basic/Targets/Sparc.h1
-rw-r--r--lib/Basic/Targets/SystemZ.cpp2
-rw-r--r--lib/Basic/Targets/X86.cpp20
-rw-r--r--lib/Basic/Targets/X86.h39
-rw-r--r--lib/Basic/TokenKinds.cpp20
-rw-r--r--lib/CodeGen/BackendUtil.cpp85
-rw-r--r--lib/CodeGen/CGAtomic.cpp9
-rw-r--r--lib/CodeGen/CGBlocks.cpp5
-rw-r--r--lib/CodeGen/CGBuiltin.cpp518
-rw-r--r--lib/CodeGen/CGCUDANV.cpp23
-rw-r--r--lib/CodeGen/CGCXX.cpp6
-rw-r--r--lib/CodeGen/CGCXXABI.cpp4
-rw-r--r--lib/CodeGen/CGCXXABI.h2
-rw-r--r--lib/CodeGen/CGCall.cpp84
-rw-r--r--lib/CodeGen/CGClass.cpp51
-rw-r--r--lib/CodeGen/CGCleanup.cpp11
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp97
-rw-r--r--lib/CodeGen/CGDecl.cpp39
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp15
-rw-r--r--lib/CodeGen/CGException.cpp8
-rw-r--r--lib/CodeGen/CGExpr.cpp90
-rw-r--r--lib/CodeGen/CGExprAgg.cpp26
-rw-r--r--lib/CodeGen/CGExprCXX.cpp45
-rw-r--r--lib/CodeGen/CGExprComplex.cpp4
-rw-r--r--lib/CodeGen/CGExprConstant.cpp10
-rw-r--r--lib/CodeGen/CGExprScalar.cpp223
-rw-r--r--lib/CodeGen/CGLoopInfo.cpp60
-rw-r--r--lib/CodeGen/CGLoopInfo.h12
-rw-r--r--lib/CodeGen/CGNonTrivialStruct.cpp2
-rw-r--r--lib/CodeGen/CGObjC.cpp4
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp13
-rw-r--r--lib/CodeGen/CGObjCMac.cpp47
-rw-r--r--lib/CodeGen/CGOpenMPRuntime.cpp1214
-rw-r--r--lib/CodeGen/CGOpenMPRuntime.h106
-rw-r--r--lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp128
-rw-r--r--lib/CodeGen/CGOpenMPRuntimeNVPTX.h12
-rw-r--r--lib/CodeGen/CGStmt.cpp72
-rw-r--r--lib/CodeGen/CGStmtOpenMP.cpp160
-rw-r--r--lib/CodeGen/CGVTables.cpp92
-rw-r--r--lib/CodeGen/CodeGenAction.cpp41
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp56
-rw-r--r--lib/CodeGen/CodeGenFunction.h15
-rw-r--r--lib/CodeGen/CodeGenModule.cpp233
-rw-r--r--lib/CodeGen/CodeGenModule.h15
-rw-r--r--lib/CodeGen/CodeGenPGO.cpp2
-rw-r--r--lib/CodeGen/CodeGenPGO.h4
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp25
-rw-r--r--lib/CodeGen/ConstantInitBuilder.cpp2
-rw-r--r--lib/CodeGen/CoverageMappingGen.cpp27
-rw-r--r--lib/CodeGen/CoverageMappingGen.h8
-rw-r--r--lib/CodeGen/EHScopeStack.h4
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp246
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp17
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp15
-rw-r--r--lib/CodeGen/ObjectFilePCHContainerOperations.cpp12
-rw-r--r--lib/CodeGen/TargetInfo.cpp362
-rw-r--r--lib/CrossTU/CrossTranslationUnit.cpp261
-rw-r--r--lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp6
-rw-r--r--lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp33
-rw-r--r--lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp34
-rw-r--r--lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp50
-rw-r--r--lib/Driver/Action.cpp14
-rw-r--r--lib/Driver/Compilation.cpp2
-rw-r--r--lib/Driver/Driver.cpp524
-rw-r--r--lib/Driver/DriverOptions.cpp17
-rw-r--r--lib/Driver/Phases.cpp1
-rw-r--r--lib/Driver/SanitizerArgs.cpp40
-rw-r--r--lib/Driver/ToolChain.cpp32
-rw-r--r--lib/Driver/ToolChains/AMDGPU.cpp2
-rw-r--r--lib/Driver/ToolChains/AVR.cpp2
-rw-r--r--lib/Driver/ToolChains/Ananas.cpp4
-rw-r--r--lib/Driver/ToolChains/Arch/AArch64.cpp1
-rw-r--r--lib/Driver/ToolChains/Arch/ARM.cpp50
-rw-r--r--lib/Driver/ToolChains/Arch/Mips.cpp25
-rw-r--r--lib/Driver/ToolChains/Arch/Mips.h3
-rw-r--r--lib/Driver/ToolChains/Arch/PPC.cpp4
-rw-r--r--lib/Driver/ToolChains/Arch/RISCV.cpp311
-rw-r--r--lib/Driver/ToolChains/Arch/RISCV.h3
-rw-r--r--lib/Driver/ToolChains/Arch/X86.cpp1
-rw-r--r--lib/Driver/ToolChains/BareMetal.cpp2
-rw-r--r--lib/Driver/ToolChains/Clang.cpp618
-rw-r--r--lib/Driver/ToolChains/Clang.h18
-rw-r--r--lib/Driver/ToolChains/CloudABI.cpp2
-rw-r--r--lib/Driver/ToolChains/CommonArgs.cpp356
-rw-r--r--lib/Driver/ToolChains/CommonArgs.h16
-rw-r--r--lib/Driver/ToolChains/CrossWindows.cpp4
-rw-r--r--lib/Driver/ToolChains/Cuda.cpp12
-rw-r--r--lib/Driver/ToolChains/Darwin.cpp41
-rw-r--r--lib/Driver/ToolChains/DragonFly.cpp4
-rw-r--r--lib/Driver/ToolChains/FreeBSD.cpp24
-rw-r--r--lib/Driver/ToolChains/FreeBSD.h2
-rw-r--r--lib/Driver/ToolChains/Fuchsia.cpp4
-rw-r--r--lib/Driver/ToolChains/Fuchsia.h4
-rw-r--r--lib/Driver/ToolChains/Gnu.cpp23
-rw-r--r--lib/Driver/ToolChains/HIP.cpp64
-rw-r--r--lib/Driver/ToolChains/HIP.h3
-rw-r--r--lib/Driver/ToolChains/Hexagon.cpp4
-rw-r--r--lib/Driver/ToolChains/InterfaceStubs.cpp37
-rw-r--r--lib/Driver/ToolChains/InterfaceStubs.h36
-rw-r--r--lib/Driver/ToolChains/Linux.cpp15
-rw-r--r--lib/Driver/ToolChains/MSP430.cpp2
-rw-r--r--lib/Driver/ToolChains/MSVC.cpp17
-rw-r--r--lib/Driver/ToolChains/MSVC.h14
-rw-r--r--lib/Driver/ToolChains/MinGW.cpp4
-rw-r--r--lib/Driver/ToolChains/MinGW.h3
-rw-r--r--lib/Driver/ToolChains/Minix.cpp4
-rw-r--r--lib/Driver/ToolChains/Myriad.cpp6
-rw-r--r--lib/Driver/ToolChains/NaCl.cpp2
-rw-r--r--lib/Driver/ToolChains/NetBSD.cpp25
-rw-r--r--lib/Driver/ToolChains/OpenBSD.cpp4
-rw-r--r--lib/Driver/ToolChains/PPCLinux.cpp5
-rw-r--r--lib/Driver/ToolChains/PS4CPU.cpp6
-rw-r--r--lib/Driver/ToolChains/RISCVToolchain.cpp9
-rw-r--r--lib/Driver/ToolChains/RISCVToolchain.h1
-rw-r--r--lib/Driver/ToolChains/Solaris.cpp30
-rw-r--r--lib/Driver/ToolChains/WebAssembly.cpp31
-rw-r--r--lib/Driver/ToolChains/XCore.cpp4
-rw-r--r--lib/Driver/Types.cpp131
-rw-r--r--lib/Driver/XRayArgs.cpp2
-rw-r--r--lib/Format/BreakableToken.cpp11
-rw-r--r--lib/Format/ContinuationIndenter.cpp23
-rw-r--r--lib/Format/Encoding.h3
-rw-r--r--lib/Format/Format.cpp246
-rw-r--r--lib/Format/FormatToken.h13
-rw-r--r--lib/Format/FormatTokenLexer.cpp20
-rw-r--r--lib/Format/FormatTokenLexer.h1
-rw-r--r--lib/Format/NamespaceEndCommentsFixer.cpp16
-rw-r--r--lib/Format/TokenAnnotator.cpp132
-rw-r--r--lib/Format/TokenAnnotator.h3
-rw-r--r--lib/Format/UnwrappedLineFormatter.cpp63
-rw-r--r--lib/Format/UnwrappedLineParser.cpp41
-rw-r--r--lib/Format/UnwrappedLineParser.h2
-rw-r--r--lib/Format/WhitespaceManager.cpp41
-rw-r--r--lib/Frontend/ASTConsumers.cpp8
-rw-r--r--lib/Frontend/ASTUnit.cpp74
-rw-r--r--lib/Frontend/ChainedIncludesSource.cpp2
-rw-r--r--lib/Frontend/CompilerInstance.cpp117
-rw-r--r--lib/Frontend/CompilerInvocation.cpp376
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp16
-rw-r--r--lib/Frontend/DependencyFile.cpp25
-rw-r--r--lib/Frontend/DependencyGraph.cpp4
-rw-r--r--lib/Frontend/FrontendAction.cpp29
-rw-r--r--lib/Frontend/FrontendActions.cpp61
-rw-r--r--lib/Frontend/FrontendOptions.cpp37
-rw-r--r--lib/Frontend/HeaderIncludeGen.cpp5
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp19
-rw-r--r--lib/Frontend/InitPreprocessor.cpp79
-rw-r--r--lib/Frontend/InterfaceStubFunctionsConsumer.cpp106
-rw-r--r--lib/Frontend/ModuleDependencyCollector.cpp8
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp4
-rw-r--r--lib/Frontend/PrecompiledPreamble.cpp24
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp2
-rw-r--r--lib/Frontend/Rewrite/FixItRewriter.cpp2
-rw-r--r--lib/Frontend/Rewrite/FrontendActions.cpp15
-rw-r--r--lib/Frontend/Rewrite/HTMLPrint.cpp2
-rw-r--r--lib/Frontend/Rewrite/InclusionRewriter.cpp180
-rw-r--r--lib/Frontend/Rewrite/RewriteModernObjC.cpp45
-rw-r--r--lib/Frontend/Rewrite/RewriteObjC.cpp23
-rw-r--r--lib/Frontend/SerializedDiagnosticPrinter.cpp8
-rw-r--r--lib/Frontend/TextDiagnostic.cpp11
-rw-r--r--lib/Frontend/VerifyDiagnosticConsumer.cpp11
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp99
-rw-r--r--lib/Headers/__clang_cuda_intrinsics.h10
-rw-r--r--lib/Headers/altivec.h85
-rw-r--r--lib/Headers/arm_acle.h24
-rw-r--r--lib/Headers/avx512fintrin.h27
-rw-r--r--lib/Headers/bmiintrin.h175
-rw-r--r--lib/Headers/cpuid.h4
-rw-r--r--lib/Headers/emmintrin.h6
-rw-r--r--lib/Headers/ia32intrin.h68
-rw-r--r--lib/Headers/immintrin.h3
-rw-r--r--lib/Headers/opencl-c-base.h19
-rw-r--r--lib/Headers/opencl-c.h212
-rw-r--r--lib/Headers/ppc_wrappers/emmintrin.h6
-rw-r--r--lib/Headers/ppc_wrappers/mm_malloc.h6
-rw-r--r--lib/Headers/ppc_wrappers/mmintrin.h7
-rw-r--r--lib/Headers/ppc_wrappers/pmmintrin.h150
-rw-r--r--lib/Headers/ppc_wrappers/smmintrin.h85
-rw-r--r--lib/Headers/ppc_wrappers/tmmintrin.h495
-rw-r--r--lib/Headers/ppc_wrappers/xmmintrin.h6
-rw-r--r--lib/Index/CodegenNameGenerator.cpp36
-rw-r--r--lib/Index/IndexSymbol.cpp2
-rw-r--r--lib/Index/IndexingAction.cpp178
-rw-r--r--lib/Index/USRGeneration.cpp3
-rw-r--r--lib/Lex/DependencyDirectivesSourceMinimizer.cpp250
-rw-r--r--lib/Lex/HeaderMap.cpp8
-rw-r--r--lib/Lex/HeaderSearch.cpp348
-rw-r--r--lib/Lex/Lexer.cpp9
-rw-r--r--lib/Lex/MacroArgs.cpp20
-rw-r--r--lib/Lex/ModuleMap.cpp73
-rw-r--r--lib/Lex/PPDirectives.cpp391
-rw-r--r--lib/Lex/PPLexerChange.cpp25
-rw-r--r--lib/Lex/PPMacroExpansion.cpp52
-rw-r--r--lib/Lex/Pragma.cpp85
-rw-r--r--lib/Lex/Preprocessor.cpp13
-rw-r--r--lib/Lex/TokenLexer.cpp16
-rw-r--r--lib/Lex/UnicodeCharSets.h2
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp2
-rw-r--r--lib/Parse/ParseDecl.cpp130
-rw-r--r--lib/Parse/ParseDeclCXX.cpp16
-rw-r--r--lib/Parse/ParseExpr.cpp39
-rw-r--r--lib/Parse/ParseExprCXX.cpp77
-rw-r--r--lib/Parse/ParseInit.cpp27
-rw-r--r--lib/Parse/ParseObjc.cpp4
-rw-r--r--lib/Parse/ParseOpenMP.cpp478
-rw-r--r--lib/Parse/ParsePragma.cpp136
-rw-r--r--lib/Parse/ParseStmt.cpp26
-rw-r--r--lib/Parse/ParseTemplate.cpp8
-rw-r--r--lib/Parse/ParseTentative.cpp7
-rw-r--r--lib/Parse/Parser.cpp47
-rw-r--r--lib/Rewrite/Rewriter.cpp11
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp82
-rw-r--r--lib/Sema/DeclSpec.cpp15
-rw-r--r--lib/Sema/OpenCLBuiltins.td744
-rw-r--r--lib/Sema/ParsedAttr.cpp65
-rw-r--r--lib/Sema/Sema.cpp91
-rw-r--r--lib/Sema/SemaAccess.cpp6
-rw-r--r--lib/Sema/SemaAttr.cpp135
-rw-r--r--lib/Sema/SemaCUDA.cpp93
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp2
-rw-r--r--lib/Sema/SemaCast.cpp17
-rw-r--r--lib/Sema/SemaChecking.cpp612
-rw-r--r--lib/Sema/SemaCodeComplete.cpp3
-rw-r--r--lib/Sema/SemaConcept.cpp125
-rw-r--r--lib/Sema/SemaCoroutine.cpp2
-rw-r--r--lib/Sema/SemaDecl.cpp884
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1101
-rw-r--r--lib/Sema/SemaDeclCXX.cpp577
-rw-r--r--lib/Sema/SemaDeclObjC.cpp14
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp23
-rw-r--r--lib/Sema/SemaExpr.cpp991
-rw-r--r--lib/Sema/SemaExprCXX.cpp295
-rw-r--r--lib/Sema/SemaExprMember.cpp20
-rw-r--r--lib/Sema/SemaExprObjC.cpp4
-rw-r--r--lib/Sema/SemaInit.cpp1210
-rw-r--r--lib/Sema/SemaLambda.cpp127
-rw-r--r--lib/Sema/SemaLookup.cpp853
-rw-r--r--lib/Sema/SemaModule.cpp2
-rw-r--r--lib/Sema/SemaObjCProperty.cpp14
-rw-r--r--lib/Sema/SemaOpenMP.cpp1880
-rw-r--r--lib/Sema/SemaOverload.cpp653
-rw-r--r--lib/Sema/SemaStmt.cpp151
-rw-r--r--lib/Sema/SemaStmtAsm.cpp32
-rw-r--r--lib/Sema/SemaStmtAttr.cpp31
-rw-r--r--lib/Sema/SemaTemplate.cpp274
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp47
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp69
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp213
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp74
-rw-r--r--lib/Sema/SemaType.cpp214
-rw-r--r--lib/Sema/TreeTransform.h220
-rw-r--r--lib/Sema/TypeLocBuilder.cpp2
-rw-r--r--lib/Sema/TypeLocBuilder.h12
-rw-r--r--lib/Serialization/ASTCommon.cpp5
-rw-r--r--lib/Serialization/ASTReader.cpp223
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp171
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp86
-rw-r--r--lib/Serialization/ASTWriter.cpp174
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp15
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp50
-rw-r--r--lib/Serialization/GlobalModuleIndex.cpp49
-rw-r--r--lib/Serialization/ModuleManager.cpp35
-rw-r--r--lib/Serialization/PCHContainerOperations.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp11
-rw-r--r--lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp72
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp27
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp23
-rw-r--r--lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/CastValueChecker.cpp445
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp15
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp43
-rw-r--r--lib/StaticAnalyzer/Checkers/ChrootChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CloneChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/ConversionChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp106
-rw-r--r--lib/StaticAnalyzer/Checkers/DebugCheckers.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp21
-rw-r--r--lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp25
-rw-r--r--lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp54
-rw-r--r--lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp18
-rw-r--r--lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp264
-rw-r--r--lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp19
-rw-r--r--lib/StaticAnalyzer/Checkers/IteratorChecker.cpp51
-rw-r--r--lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp14
-rw-r--r--lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp42
-rw-r--r--lib/StaticAnalyzer/Checkers/MIGChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp24
-rw-r--r--lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.h6
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp43
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp1287
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/MoveChecker.cpp23
-rw-r--r--lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp31
-rw-r--r--lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp36
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp20
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/PaddingChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp18
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp14
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp10
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h2
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp61
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h18
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp22
-rw-r--r--lib/StaticAnalyzer/Checkers/StreamChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/Taint.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/Taint.h6
-rw-r--r--lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp11
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ValistChecker.cpp44
-rw-r--r--lib/StaticAnalyzer/Checkers/VforkChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp203
-rwxr-xr-xlib/StaticAnalyzer/Checkers/Yaml.h59
-rw-r--r--lib/StaticAnalyzer/Core/AnalysisManager.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp19
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp1858
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp660
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp24
-rw-r--r--lib/StaticAnalyzer/Core/Checker.cpp8
-rw-r--r--lib/StaticAnalyzer/Core/CheckerHelpers.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/CommonBugCategories.cpp1
-rw-r--r--lib/StaticAnalyzer/Core/DynamicType.cpp229
-rw-r--r--lib/StaticAnalyzer/Core/DynamicTypeMap.cpp97
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp1
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp120
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp91
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp36
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp5
-rw-r--r--lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp50
-rw-r--r--lib/StaticAnalyzer/Core/LoopUnrolling.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp5
-rw-r--r--lib/StaticAnalyzer/Core/PlistDiagnostics.cpp157
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/RangeConstraintManager.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp89
-rw-r--r--lib/StaticAnalyzer/Core/SMTConstraintManager.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/SarifDiagnostics.cpp123
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/WorkList.cpp12
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp106
-rw-r--r--lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp23
-rw-r--r--lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp24
-rw-r--r--lib/StaticAnalyzer/Frontend/FrontendActions.cpp2
-rw-r--r--lib/StaticAnalyzer/Frontend/ModelInjector.cpp3
-rw-r--r--lib/Tooling/ASTDiff/ASTDiff.cpp16
-rw-r--r--lib/Tooling/AllTUsExecution.cpp5
-rw-r--r--lib/Tooling/ArgumentsAdjusters.cpp16
-rw-r--r--lib/Tooling/CommonOptionsParser.cpp2
-rw-r--r--lib/Tooling/CompilationDatabase.cpp4
-rw-r--r--lib/Tooling/Core/Replacement.cpp11
-rw-r--r--lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp234
-rw-r--r--lib/Tooling/DependencyScanning/DependencyScanningService.cpp19
-rw-r--r--lib/Tooling/DependencyScanning/DependencyScanningTool.cpp71
-rw-r--r--lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp140
-rw-r--r--lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp2
-rw-r--r--lib/Tooling/Inclusions/HeaderIncludes.cpp14
-rw-r--r--lib/Tooling/Inclusions/IncludeStyle.cpp1
-rw-r--r--lib/Tooling/InterpolatingCompilationDatabase.cpp33
-rw-r--r--lib/Tooling/Refactoring.cpp5
-rw-r--r--lib/Tooling/Refactoring/ASTSelectionRequirements.cpp2
-rw-r--r--lib/Tooling/Refactoring/Extract/Extract.cpp2
-rw-r--r--lib/Tooling/Refactoring/Extract/SourceExtraction.cpp8
-rw-r--r--lib/Tooling/Refactoring/RefactoringActions.cpp4
-rw-r--r--lib/Tooling/Refactoring/Rename/RenamingAction.cpp4
-rw-r--r--lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp2
-rw-r--r--lib/Tooling/Refactoring/Rename/USRFindingAction.cpp6
-rw-r--r--lib/Tooling/Refactoring/SourceCode.cpp31
-rw-r--r--lib/Tooling/Refactoring/Stencil.cpp175
-rw-r--r--lib/Tooling/Refactoring/Transformer.cpp263
-rw-r--r--lib/Tooling/RefactoringCallbacks.cpp2
-rw-r--r--lib/Tooling/StandaloneExecution.cpp2
-rw-r--r--lib/Tooling/Syntax/BuildTree.cpp12
-rw-r--r--lib/Tooling/Syntax/Tokens.cpp17
-rw-r--r--lib/Tooling/Tooling.cpp84
-rw-r--r--lib/Tooling/Transformer/CMakeLists.txt18
-rw-r--r--lib/Tooling/Transformer/RangeSelector.cpp (renamed from lib/Tooling/Refactoring/RangeSelector.cpp)56
-rw-r--r--lib/Tooling/Transformer/RewriteRule.cpp178
-rw-r--r--lib/Tooling/Transformer/SourceCode.cpp65
-rw-r--r--lib/Tooling/Transformer/SourceCodeBuilders.cpp160
-rw-r--r--lib/Tooling/Transformer/Stencil.cpp318
-rw-r--r--lib/Tooling/Transformer/Transformer.cpp72
-rw-r--r--tools/clang-format/ClangFormat.cpp284
-rw-r--r--tools/clang-offload-wrapper/CMakeLists.txt23
-rw-r--r--tools/clang-offload-wrapper/ClangOffloadWrapper.cpp371
-rw-r--r--tools/driver/cc1_main.cpp44
-rw-r--r--tools/driver/cc1as_main.cpp38
-rw-r--r--tools/driver/driver.cpp8
-rw-r--r--utils/TableGen/ClangASTNodesEmitter.cpp10
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp264
-rw-r--r--utils/TableGen/ClangCommentCommandInfoEmitter.cpp8
-rw-r--r--utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp9
-rw-r--r--utils/TableGen/ClangDataCollectorsEmitter.cpp5
-rw-r--r--utils/TableGen/ClangDiagnosticsEmitter.cpp18
-rw-r--r--utils/TableGen/ClangOpcodesEmitter.cpp357
-rw-r--r--utils/TableGen/ClangOpenCLBuiltinEmitter.cpp540
-rw-r--r--utils/TableGen/ClangOptionDocEmitter.cpp9
-rw-r--r--utils/TableGen/ClangSACheckersEmitter.cpp5
-rw-r--r--utils/TableGen/ClangTypeNodesEmitter.cpp220
-rw-r--r--utils/TableGen/NeonEmitter.cpp60
-rw-r--r--utils/TableGen/TableGen.cpp12
-rw-r--r--utils/TableGen/TableGenBackends.h2
753 files changed, 46521 insertions, 17283 deletions
diff --git a/include/clang-c/FatalErrorHandler.h b/include/clang-c/FatalErrorHandler.h
new file mode 100644
index 000000000000..ce8ff2cae735
--- /dev/null
+++ b/include/clang-c/FatalErrorHandler.h
@@ -0,0 +1,33 @@
+/*===-- clang-c/FatalErrorHandler.h - Fatal Error Handling --------*- C -*-===*\
+|* *|
+|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
+|* Exceptions. *|
+|* See https://llvm.org/LICENSE.txt for license information. *|
+|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef LLVM_CLANG_C_FATAL_ERROR_HANDLER_H
+#define LLVM_CLANG_C_FATAL_ERROR_HANDLER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Installs error handler that prints error message to stderr and calls abort().
+ * Replaces currently installed error handler (if any).
+ */
+void clang_install_aborting_llvm_fatal_error_handler(void);
+
+/**
+ * Removes currently installed error handler (if any).
+ * If no error handler is intalled, the default strategy is to print error
+ * message to stderr and call exit(1).
+ */
+void clang_uninstall_llvm_fatal_error_handler(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 74badac740b6..226893505437 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -1356,7 +1356,12 @@ enum CXTranslationUnit_Flags {
* the case where these warnings are not of interest, as for an IDE for
* example, which typically shows only the diagnostics in the main file.
*/
- CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles = 0x4000
+ CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles = 0x4000,
+
+ /**
+ * Tells the preprocessor not to skip excluded conditional blocks.
+ */
+ CXTranslationUnit_RetainExcludedConditionalBlocks = 0x8000
};
/**
@@ -2550,7 +2555,20 @@ enum CXCursorKind {
*/
CXCursor_BuiltinBitCastExpr = 280,
- CXCursor_LastStmt = CXCursor_BuiltinBitCastExpr,
+ /** OpenMP master taskloop directive.
+ */
+ CXCursor_OMPMasterTaskLoopDirective = 281,
+
+ /** OpenMP parallel master taskloop directive.
+ */
+ CXCursor_OMPParallelMasterTaskLoopDirective = 282,
+
+ /** OpenMP master taskloop simd directive.
+ */
+ CXCursor_OMPMasterTaskLoopSimdDirective = 283,
+
+
+ CXCursor_LastStmt = CXCursor_OMPMasterTaskLoopSimdDirective,
/**
* Cursor that represents the translation unit itself.
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h
index 6943479831ec..63359294ef63 100644
--- a/include/clang/AST/APValue.h
+++ b/include/clang/AST/APValue.h
@@ -53,6 +53,34 @@ public:
void print(llvm::raw_ostream &Out, const PrintingPolicy &Policy) const;
};
+
+/// Symbolic representation of a dynamic allocation.
+class DynamicAllocLValue {
+ unsigned Index;
+
+public:
+ DynamicAllocLValue() : Index(0) {}
+ explicit DynamicAllocLValue(unsigned Index) : Index(Index + 1) {}
+ unsigned getIndex() { return Index - 1; }
+
+ explicit operator bool() const { return Index != 0; }
+
+ void *getOpaqueValue() {
+ return reinterpret_cast<void *>(static_cast<uintptr_t>(Index)
+ << NumLowBitsAvailable);
+ }
+ static DynamicAllocLValue getFromOpaqueValue(void *Value) {
+ DynamicAllocLValue V;
+ V.Index = reinterpret_cast<uintptr_t>(Value) >> NumLowBitsAvailable;
+ return V;
+ }
+
+ static unsigned getMaxIndex() {
+ return (std::numeric_limits<unsigned>::max() >> NumLowBitsAvailable) - 1;
+ }
+
+ static constexpr int NumLowBitsAvailable = 3;
+};
}
namespace llvm {
@@ -67,6 +95,17 @@ template<> struct PointerLikeTypeTraits<clang::TypeInfoLValue> {
// to include Type.h.
static constexpr int NumLowBitsAvailable = 3;
};
+
+template<> struct PointerLikeTypeTraits<clang::DynamicAllocLValue> {
+ static void *getAsVoidPointer(clang::DynamicAllocLValue V) {
+ return V.getOpaqueValue();
+ }
+ static clang::DynamicAllocLValue getFromVoidPointer(void *P) {
+ return clang::DynamicAllocLValue::getFromOpaqueValue(P);
+ }
+ static constexpr int NumLowBitsAvailable =
+ clang::DynamicAllocLValue::NumLowBitsAvailable;
+};
}
namespace clang {
@@ -97,13 +136,15 @@ public:
};
class LValueBase {
- typedef llvm::PointerUnion<const ValueDecl *, const Expr *, TypeInfoLValue>
+ typedef llvm::PointerUnion<const ValueDecl *, const Expr *, TypeInfoLValue,
+ DynamicAllocLValue>
PtrTy;
public:
LValueBase() : Local{} {}
LValueBase(const ValueDecl *P, unsigned I = 0, unsigned V = 0);
LValueBase(const Expr *P, unsigned I = 0, unsigned V = 0);
+ static LValueBase getDynamicAlloc(DynamicAllocLValue LV, QualType Type);
static LValueBase getTypeInfo(TypeInfoLValue LV, QualType TypeInfo);
template <class T>
@@ -124,6 +165,7 @@ public:
unsigned getCallIndex() const;
unsigned getVersion() const;
QualType getTypeInfoType() const;
+ QualType getDynamicAllocType() const;
friend bool operator==(const LValueBase &LHS, const LValueBase &RHS);
friend bool operator!=(const LValueBase &LHS, const LValueBase &RHS) {
@@ -140,6 +182,8 @@ public:
LocalState Local;
/// The type std::type_info, if this is a TypeInfoLValue.
void *TypeInfoType;
+ /// The QualType, if this is a DynamicAllocLValue.
+ void *DynamicAllocType;
};
};
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 1d1aaf4fb115..5e2f4031d96c 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -139,6 +139,12 @@ class FullComment;
} // namespace comments
+namespace interp {
+
+class Context;
+
+} // namespace interp
+
struct TypeInfo {
uint64_t Width = 0;
unsigned Align = 0;
@@ -179,7 +185,8 @@ private:
mutable llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes;
mutable llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes;
mutable llvm::FoldingSet<MemberPointerType> MemberPointerTypes;
- mutable llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes;
+ mutable llvm::ContextualFoldingSet<ConstantArrayType, ASTContext &>
+ ConstantArrayTypes;
mutable llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes;
mutable std::vector<VariableArrayType*> VariableArrayTypes;
mutable llvm::FoldingSet<DependentSizedArrayType> DependentSizedArrayTypes;
@@ -507,6 +514,8 @@ private:
/// need to be consistently numbered for the mangler).
llvm::DenseMap<const DeclContext *, std::unique_ptr<MangleNumberingContext>>
MangleNumberingContexts;
+ llvm::DenseMap<const Decl *, std::unique_ptr<MangleNumberingContext>>
+ ExtraMangleNumberingContexts;
/// Side-table of mangling numbers for declarations which rarely
/// need them (like static local vars).
@@ -564,6 +573,7 @@ private:
const TargetInfo *Target = nullptr;
const TargetInfo *AuxTarget = nullptr;
clang::PrintingPolicy PrintingPolicy;
+ std::unique_ptr<interp::Context> InterpContext;
public:
IdentifierTable &Idents;
@@ -573,6 +583,9 @@ public:
IntrusiveRefCntPtr<ExternalASTSource> ExternalSource;
ASTMutationListener *Listener = nullptr;
+ /// Returns the clang bytecode interpreter context.
+ interp::Context &getInterpContext();
+
/// Container for either a single DynTypedNode or for an ArrayRef to
/// DynTypedNode. For use with ParentMap.
class DynTypedNodeList {
@@ -729,71 +742,49 @@ public:
/// True if comments are already loaded from ExternalASTSource.
mutable bool CommentsLoaded = false;
- class RawCommentAndCacheFlags {
- public:
- enum Kind {
- /// We searched for a comment attached to the particular declaration, but
- /// didn't find any.
- ///
- /// getRaw() == 0.
- NoCommentInDecl = 0,
-
- /// We have found a comment attached to this particular declaration.
- ///
- /// getRaw() != 0.
- FromDecl,
-
- /// This declaration does not have an attached comment, and we have
- /// searched the redeclaration chain.
- ///
- /// If getRaw() == 0, the whole redeclaration chain does not have any
- /// comments.
- ///
- /// If getRaw() != 0, it is a comment propagated from other
- /// redeclaration.
- FromRedecl
- };
-
- Kind getKind() const LLVM_READONLY {
- return Data.getInt();
- }
-
- void setKind(Kind K) {
- Data.setInt(K);
- }
-
- const RawComment *getRaw() const LLVM_READONLY {
- return Data.getPointer();
- }
-
- void setRaw(const RawComment *RC) {
- Data.setPointer(RC);
- }
-
- const Decl *getOriginalDecl() const LLVM_READONLY {
- return OriginalDecl;
- }
-
- void setOriginalDecl(const Decl *Orig) {
- OriginalDecl = Orig;
- }
-
- private:
- llvm::PointerIntPair<const RawComment *, 2, Kind> Data;
- const Decl *OriginalDecl;
- };
+ /// Mapping from declaration to directly attached comment.
+ ///
+ /// Raw comments are owned by Comments list. This mapping is populated
+ /// lazily.
+ mutable llvm::DenseMap<const Decl *, const RawComment *> DeclRawComments;
- /// Mapping from declarations to comments attached to any
- /// redeclaration.
+ /// Mapping from canonical declaration to the first redeclaration in chain
+ /// that has a comment attached.
///
/// Raw comments are owned by Comments list. This mapping is populated
/// lazily.
- mutable llvm::DenseMap<const Decl *, RawCommentAndCacheFlags> RedeclComments;
+ mutable llvm::DenseMap<const Decl *, const Decl *> RedeclChainComments;
+
+ /// Keeps track of redeclaration chains that don't have any comment attached.
+ /// Mapping from canonical declaration to redeclaration chain that has no
+ /// comments attached to any redeclaration. Specifically it's mapping to
+ /// the last redeclaration we've checked.
+ ///
+ /// Shall not contain declarations that have comments attached to any
+ /// redeclaration in their chain.
+ mutable llvm::DenseMap<const Decl *, const Decl *> CommentlessRedeclChains;
/// Mapping from declarations to parsed comments attached to any
/// redeclaration.
mutable llvm::DenseMap<const Decl *, comments::FullComment *> ParsedComments;
+ /// Attaches \p Comment to \p OriginalD and to its redeclaration chain
+ /// and removes the redeclaration chain from the set of commentless chains.
+ ///
+ /// Don't do anything if a comment has already been attached to \p OriginalD
+ /// or its redeclaration chain.
+ void cacheRawCommentForDecl(const Decl &OriginalD,
+ const RawComment &Comment) const;
+
+ /// \returns searches \p CommentsInFile for doc comment for \p D.
+ ///
+ /// \p RepresentativeLocForDecl is used as a location for searching doc
+ /// comments. \p CommentsInFile is a mapping offset -> comment of files in the
+ /// same file where \p RepresentativeLocForDecl is.
+ RawComment *getRawCommentForDeclNoCacheImpl(
+ const Decl *D, const SourceLocation RepresentativeLocForDecl,
+ const std::map<unsigned, RawComment *> &CommentsInFile) const;
+
/// Return the documentation comment attached to a given declaration,
/// without looking into cache.
RawComment *getRawCommentForDeclNoCache(const Decl *D) const;
@@ -818,6 +809,16 @@ public:
getRawCommentForAnyRedecl(const Decl *D,
const Decl **OriginalDecl = nullptr) const;
+ /// Searches existing comments for doc comments that should be attached to \p
+ /// Decls. If any doc comment is found, it is parsed.
+ ///
+ /// Requirement: All \p Decls are in the same file.
+ ///
+ /// If the last comment in the file is already attached we assume
+ /// there are not comments left to be attached to \p Decls.
+ void attachCommentsToJustParsedDecls(ArrayRef<Decl *> Decls,
+ const Preprocessor *PP);
+
/// Return parsed documentation comment attached to a given declaration.
/// Returns nullptr if no comment is attached.
///
@@ -1054,6 +1055,9 @@ public:
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
CanQualType Id##Ty;
#include "clang/Basic/OpenCLExtensionTypes.def"
+#define SVE_TYPE(Name, Id, SingletonId) \
+ CanQualType SingletonId;
+#include "clang/Basic/AArch64SVEACLETypes.def"
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
mutable QualType AutoDeductTy; // Deduction against 'auto'.
@@ -1329,6 +1333,7 @@ public:
/// Return the unique reference to the type for a constant array of
/// the specified element type.
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize,
+ const Expr *SizeExpr,
ArrayType::ArraySizeModifier ASM,
unsigned IndexTypeQuals) const;
@@ -1498,8 +1503,7 @@ public:
bool isKindOf) const;
QualType getObjCTypeParamType(const ObjCTypeParamDecl *Decl,
- ArrayRef<ObjCProtocolDecl *> protocols,
- QualType Canonical = QualType()) const;
+ ArrayRef<ObjCProtocolDecl *> protocols) const;
bool ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *Decl);
@@ -2054,6 +2058,11 @@ public:
/// types.
bool areCompatibleVectorTypes(QualType FirstVec, QualType SecondVec);
+ /// Return true if the type has been explicitly qualified with ObjC ownership.
+ /// A type may be implicitly qualified with ownership under ObjC ARC, and in
+ /// some cases the compiler treats these differently.
+ bool hasDirectOwnershipQualifier(QualType Ty) const;
+
/// Return true if this is an \c NSObject object with its \c NSObject
/// attribute set.
static bool isObjCNSObjectType(QualType Ty) {
@@ -2577,10 +2586,12 @@ public:
return T == getObjCSelType();
}
- bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS,
+ bool ObjCQualifiedIdTypesAreCompatible(const ObjCObjectPointerType *LHS,
+ const ObjCObjectPointerType *RHS,
bool ForCompare);
- bool ObjCQualifiedClassTypesAreCompatible(QualType LHS, QualType RHS);
+ bool ObjCQualifiedClassTypesAreCompatible(const ObjCObjectPointerType *LHS,
+ const ObjCObjectPointerType *RHS);
// Check the safety of assignment from LHS to RHS
bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
@@ -2802,6 +2813,9 @@ public:
/// Retrieve the context for computing mangling numbers in the given
/// DeclContext.
MangleNumberingContext &getManglingNumberContext(const DeclContext *DC);
+ enum NeedExtraManglingDecl_t { NeedExtraManglingDecl };
+ MangleNumberingContext &getManglingNumberContext(NeedExtraManglingDecl_t,
+ const Decl *D);
std::unique_ptr<MangleNumberingContext> createMangleNumberingContext() const;
diff --git a/include/clang/AST/ASTFwd.h b/include/clang/AST/ASTFwd.h
index 93919bbdd52f..25c321485443 100644
--- a/include/clang/AST/ASTFwd.h
+++ b/include/clang/AST/ASTFwd.h
@@ -24,7 +24,7 @@ class Stmt;
#include "clang/AST/StmtNodes.inc"
class Type;
#define TYPE(DERIVED, BASE) class DERIVED##Type;
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
class CXXCtorInitializer;
} // end namespace clang
diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h
index 4a55c120a457..c82dcab35db5 100644
--- a/include/clang/AST/ASTImporter.h
+++ b/include/clang/AST/ASTImporter.h
@@ -87,6 +87,10 @@ class TypeSourceInfo;
using NonEquivalentDeclSet = llvm::DenseSet<std::pair<Decl *, Decl *>>;
using ImportedCXXBaseSpecifierMap =
llvm::DenseMap<const CXXBaseSpecifier *, CXXBaseSpecifier *>;
+ using FileIDImportHandlerType =
+ std::function<void(FileID /*ToID*/, FileID /*FromID*/)>;
+
+ enum class ODRHandlingType { Conservative, Liberal };
// An ImportPath is the list of the AST nodes which we visit during an
// Import call.
@@ -210,6 +214,8 @@ class TypeSourceInfo;
};
private:
+ FileIDImportHandlerType FileIDImportHandler;
+
std::shared_ptr<ASTImporterSharedState> SharedState = nullptr;
/// The path which we go through during the import of a given AST node.
@@ -232,6 +238,8 @@ class TypeSourceInfo;
/// Whether to perform a minimal import.
bool Minimal;
+ ODRHandlingType ODRHandling;
+
/// Whether the last diagnostic came from the "from" context.
bool LastDiagFromFrom = false;
@@ -310,10 +318,20 @@ class TypeSourceInfo;
virtual ~ASTImporter();
+ /// Set a callback function for FileID import handling.
+ /// The function is invoked when a FileID is imported from the From context.
+ /// The imported FileID in the To context and the original FileID in the
+ /// From context is passed to it.
+ void setFileIDImportHandler(FileIDImportHandlerType H) {
+ FileIDImportHandler = H;
+ }
+
/// Whether the importer will perform a minimal import, creating
/// to-be-completed forward declarations when possible.
bool isMinimalImport() const { return Minimal; }
+ void setODRHandling(ODRHandlingType T) { ODRHandling = T; }
+
/// \brief Import the given object, returns the result.
///
/// \param To Import the object into this variable.
@@ -366,6 +384,20 @@ class TypeSourceInfo;
/// imported. If it does not exist nullptr is returned.
TranslationUnitDecl *GetFromTU(Decl *ToD);
+ /// Return the declaration in the "from" context from which the declaration
+ /// in the "to" context was imported. If it was not imported or of the wrong
+ /// type a null value is returned.
+ template <typename DeclT>
+ llvm::Optional<DeclT *> getImportedFromDecl(const DeclT *ToD) const {
+ auto FromI = ImportedFromDecls.find(ToD);
+ if (FromI == ImportedFromDecls.end())
+ return {};
+ auto *FromD = dyn_cast<DeclT>(FromI->second);
+ if (!FromD)
+ return {};
+ return FromD;
+ }
+
/// Import the given declaration context from the "from"
/// AST context into the "to" AST context.
///
@@ -491,12 +523,11 @@ class TypeSourceInfo;
///
/// \param NumDecls the number of conflicting declarations in \p Decls.
///
- /// \returns the name that the newly-imported declaration should have.
- virtual DeclarationName HandleNameConflict(DeclarationName Name,
- DeclContext *DC,
- unsigned IDNS,
- NamedDecl **Decls,
- unsigned NumDecls);
+ /// \returns the name that the newly-imported declaration should have. Or
+ /// an error if we can't handle the name conflict.
+ virtual Expected<DeclarationName>
+ HandleNameConflict(DeclarationName Name, DeclContext *DC, unsigned IDNS,
+ NamedDecl **Decls, unsigned NumDecls);
/// Retrieve the context that AST nodes are being imported into.
ASTContext &getToContext() const { return ToContext; }
diff --git a/include/clang/AST/ASTImporterSharedState.h b/include/clang/AST/ASTImporterSharedState.h
index 3635a62deef0..829eb1c611c3 100644
--- a/include/clang/AST/ASTImporterSharedState.h
+++ b/include/clang/AST/ASTImporterSharedState.h
@@ -47,7 +47,7 @@ public:
ASTImporterSharedState() = default;
ASTImporterSharedState(TranslationUnitDecl &ToTU) {
- LookupTable = llvm::make_unique<ASTImporterLookupTable>(ToTU);
+ LookupTable = std::make_unique<ASTImporterLookupTable>(ToTU);
}
ASTImporterLookupTable *getLookupTable() { return LookupTable.get(); }
diff --git a/include/clang/AST/ASTNodeTraverser.h b/include/clang/AST/ASTNodeTraverser.h
index e43eacef86c6..0bb2aad553fb 100644
--- a/include/clang/AST/ASTNodeTraverser.h
+++ b/include/clang/AST/ASTNodeTraverser.h
@@ -237,6 +237,9 @@ public:
for (const auto &TP : *TPL)
Visit(TP);
+
+ if (const Expr *RC = TPL->getRequiresClause())
+ Visit(RC);
}
void
diff --git a/include/clang/AST/ASTStructuralEquivalence.h b/include/clang/AST/ASTStructuralEquivalence.h
index 70e0daa08a9a..36a42070fd28 100644
--- a/include/clang/AST/ASTStructuralEquivalence.h
+++ b/include/clang/AST/ASTStructuralEquivalence.h
@@ -18,7 +18,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Optional.h"
-#include <deque>
+#include <queue>
#include <utility>
namespace clang {
@@ -42,14 +42,13 @@ struct StructuralEquivalenceContext {
/// AST contexts for which we are checking structural equivalence.
ASTContext &FromCtx, &ToCtx;
- /// The set of "tentative" equivalences between two canonical
- /// declarations, mapping from a declaration in the first context to the
- /// declaration in the second context that we believe to be equivalent.
- llvm::DenseMap<Decl *, Decl *> TentativeEquivalences;
+ // Queue of from-to Decl pairs that are to be checked to determine the final
+ // result of equivalence of a starting Decl pair.
+ std::queue<std::pair<Decl *, Decl *>> DeclsToCheck;
- /// Queue of declarations in the first context whose equivalence
- /// with a declaration in the second context still needs to be verified.
- std::deque<Decl *> DeclsToCheck;
+ // Set of from-to Decl pairs that are already visited during the check
+ // (are in or were once in \c DeclsToCheck) of a starting Decl pair.
+ llvm::DenseSet<std::pair<Decl *, Decl *>> VisitedDecls;
/// Declaration (from, to) pairs that are known not to be equivalent
/// (which we have already complained about).
@@ -88,14 +87,14 @@ struct StructuralEquivalenceContext {
/// Implementation functions (all static functions in
/// ASTStructuralEquivalence.cpp) must never call this function because that
/// will wreak havoc the internal state (\c DeclsToCheck and
- /// \c TentativeEquivalences members) and can cause faulty equivalent results.
+ /// \c VisitedDecls members) and can cause faulty equivalent results.
bool IsEquivalent(Decl *D1, Decl *D2);
/// Determine whether the two types are structurally equivalent.
/// Implementation functions (all static functions in
/// ASTStructuralEquivalence.cpp) must never call this function because that
/// will wreak havoc the internal state (\c DeclsToCheck and
- /// \c TentativeEquivalences members) and can cause faulty equivalent results.
+ /// \c VisitedDecls members) and can cause faulty equivalent results.
bool IsEquivalent(QualType T1, QualType T2);
/// Find the index of the given anonymous struct/union within its
diff --git a/include/clang/AST/ASTTypeTraits.h b/include/clang/AST/ASTTypeTraits.h
index a29a04e5d242..dd4ead2f0c2b 100644
--- a/include/clang/AST/ASTTypeTraits.h
+++ b/include/clang/AST/ASTTypeTraits.h
@@ -148,7 +148,7 @@ private:
#include "clang/AST/StmtNodes.inc"
NKI_Type,
#define TYPE(DERIVED, BASE) NKI_##DERIVED##Type,
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
NKI_OMPClause,
#define OPENMP_CLAUSE(TextualSpelling, Class) NKI_##Class,
#include "clang/Basic/OpenMPKinds.def"
@@ -205,7 +205,7 @@ KIND_TO_KIND_ID(OMPClause)
#define STMT(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED)
#include "clang/AST/StmtNodes.inc"
#define TYPE(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Type)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
#define OPENMP_CLAUSE(TextualSpelling, Class) KIND_TO_KIND_ID(Class)
#include "clang/Basic/OpenMPKinds.def"
#undef KIND_TO_KIND_ID
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index 1fbed7ceebfa..d315dde6ed45 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -19,6 +19,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "clang/Basic/AttrKinds.h"
+#include "clang/Basic/AttributeCommonInfo.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/Sanitizers.h"
@@ -32,6 +33,7 @@
namespace clang {
class ASTContext;
+ class AttributeCommonInfo;
class IdentifierInfo;
class ObjCInterfaceDecl;
class Expr;
@@ -40,84 +42,79 @@ namespace clang {
class TypeSourceInfo;
/// Attr - This represents one attribute.
-class Attr {
-private:
- SourceRange Range;
- unsigned AttrKind : 16;
-
-protected:
- /// An index into the spelling list of an
- /// attribute defined in Attr.td file.
- unsigned SpellingListIndex : 4;
- unsigned Inherited : 1;
- unsigned IsPackExpansion : 1;
- unsigned Implicit : 1;
- // FIXME: These are properties of the attribute kind, not state for this
- // instance of the attribute.
- unsigned IsLateParsed : 1;
- unsigned InheritEvenIfAlreadyPresent : 1;
-
- void *operator new(size_t bytes) noexcept {
- llvm_unreachable("Attrs cannot be allocated with regular 'new'.");
- }
- void operator delete(void *data) noexcept {
- llvm_unreachable("Attrs cannot be released with regular 'delete'.");
- }
-
-public:
- // Forward so that the regular new and delete do not hide global ones.
- void *operator new(size_t Bytes, ASTContext &C,
- size_t Alignment = 8) noexcept {
- return ::operator new(Bytes, C, Alignment);
- }
- void operator delete(void *Ptr, ASTContext &C, size_t Alignment) noexcept {
- return ::operator delete(Ptr, C, Alignment);
- }
+ class Attr : public AttributeCommonInfo {
+ private:
+ unsigned AttrKind : 16;
+
+ protected:
+ /// An index into the spelling list of an
+ /// attribute defined in Attr.td file.
+ unsigned Inherited : 1;
+ unsigned IsPackExpansion : 1;
+ unsigned Implicit : 1;
+ // FIXME: These are properties of the attribute kind, not state for this
+ // instance of the attribute.
+ unsigned IsLateParsed : 1;
+ unsigned InheritEvenIfAlreadyPresent : 1;
+
+ void *operator new(size_t bytes) noexcept {
+ llvm_unreachable("Attrs cannot be allocated with regular 'new'.");
+ }
+ void operator delete(void *data) noexcept {
+ llvm_unreachable("Attrs cannot be released with regular 'delete'.");
+ }
-protected:
- Attr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex,
- bool IsLateParsed)
- : Range(R), AttrKind(AK), SpellingListIndex(SpellingListIndex),
- Inherited(false), IsPackExpansion(false), Implicit(false),
- IsLateParsed(IsLateParsed), InheritEvenIfAlreadyPresent(false) {}
+ public:
+ // Forward so that the regular new and delete do not hide global ones.
+ void *operator new(size_t Bytes, ASTContext &C,
+ size_t Alignment = 8) noexcept {
+ return ::operator new(Bytes, C, Alignment);
+ }
+ void operator delete(void *Ptr, ASTContext &C, size_t Alignment) noexcept {
+ return ::operator delete(Ptr, C, Alignment);
+ }
-public:
+ protected:
+ Attr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,
+ attr::Kind AK, bool IsLateParsed)
+ : AttributeCommonInfo(CommonInfo), AttrKind(AK), Inherited(false),
+ IsPackExpansion(false), Implicit(false), IsLateParsed(IsLateParsed),
+ InheritEvenIfAlreadyPresent(false) {}
- attr::Kind getKind() const {
- return static_cast<attr::Kind>(AttrKind);
- }
+ public:
+ attr::Kind getKind() const { return static_cast<attr::Kind>(AttrKind); }
- unsigned getSpellingListIndex() const { return SpellingListIndex; }
- const char *getSpelling() const;
+ unsigned getSpellingListIndex() const {
+ return getAttributeSpellingListIndex();
+ }
+ const char *getSpelling() const;
- SourceLocation getLocation() const { return Range.getBegin(); }
- SourceRange getRange() const { return Range; }
- void setRange(SourceRange R) { Range = R; }
+ SourceLocation getLocation() const { return getRange().getBegin(); }
- bool isInherited() const { return Inherited; }
+ bool isInherited() const { return Inherited; }
- /// Returns true if the attribute has been implicitly created instead
- /// of explicitly written by the user.
- bool isImplicit() const { return Implicit; }
- void setImplicit(bool I) { Implicit = I; }
+ /// Returns true if the attribute has been implicitly created instead
+ /// of explicitly written by the user.
+ bool isImplicit() const { return Implicit; }
+ void setImplicit(bool I) { Implicit = I; }
- void setPackExpansion(bool PE) { IsPackExpansion = PE; }
- bool isPackExpansion() const { return IsPackExpansion; }
+ void setPackExpansion(bool PE) { IsPackExpansion = PE; }
+ bool isPackExpansion() const { return IsPackExpansion; }
- // Clone this attribute.
- Attr *clone(ASTContext &C) const;
+ // Clone this attribute.
+ Attr *clone(ASTContext &C) const;
- bool isLateParsed() const { return IsLateParsed; }
+ bool isLateParsed() const { return IsLateParsed; }
- // Pretty print this attribute.
- void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const;
-};
+ // Pretty print this attribute.
+ void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const;
+ };
class TypeAttr : public Attr {
protected:
- TypeAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex,
- bool IsLateParsed)
- : Attr(AK, R, SpellingListIndex, IsLateParsed) {}
+ TypeAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,
+ attr::Kind AK, bool IsLateParsed)
+ : Attr(Context, CommonInfo, AK, IsLateParsed) {}
public:
static bool classof(const Attr *A) {
@@ -128,9 +125,9 @@ public:
class StmtAttr : public Attr {
protected:
- StmtAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex,
- bool IsLateParsed)
- : Attr(AK, R, SpellingListIndex, IsLateParsed) {}
+ StmtAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,
+ attr::Kind AK, bool IsLateParsed)
+ : Attr(Context, CommonInfo, AK, IsLateParsed) {}
public:
static bool classof(const Attr *A) {
@@ -141,9 +138,10 @@ public:
class InheritableAttr : public Attr {
protected:
- InheritableAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex,
- bool IsLateParsed, bool InheritEvenIfAlreadyPresent)
- : Attr(AK, R, SpellingListIndex, IsLateParsed) {
+ InheritableAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,
+ attr::Kind AK, bool IsLateParsed,
+ bool InheritEvenIfAlreadyPresent)
+ : Attr(Context, CommonInfo, AK, IsLateParsed) {
this->InheritEvenIfAlreadyPresent = InheritEvenIfAlreadyPresent;
}
@@ -165,9 +163,10 @@ public:
class InheritableParamAttr : public InheritableAttr {
protected:
- InheritableParamAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex,
+ InheritableParamAttr(ASTContext &Context,
+ const AttributeCommonInfo &CommonInfo, attr::Kind AK,
bool IsLateParsed, bool InheritEvenIfAlreadyPresent)
- : InheritableAttr(AK, R, SpellingListIndex, IsLateParsed,
+ : InheritableAttr(Context, CommonInfo, AK, IsLateParsed,
InheritEvenIfAlreadyPresent) {}
public:
@@ -182,11 +181,11 @@ public:
/// for the parameter.
class ParameterABIAttr : public InheritableParamAttr {
protected:
- ParameterABIAttr(attr::Kind AK, SourceRange R,
- unsigned SpellingListIndex, bool IsLateParsed,
+ ParameterABIAttr(ASTContext &Context, const AttributeCommonInfo &CommonInfo,
+ attr::Kind AK, bool IsLateParsed,
bool InheritEvenIfAlreadyPresent)
- : InheritableParamAttr(AK, R, SpellingListIndex, IsLateParsed,
- InheritEvenIfAlreadyPresent) {}
+ : InheritableParamAttr(Context, CommonInfo, AK, IsLateParsed,
+ InheritEvenIfAlreadyPresent) {}
public:
ParameterABI getABI() const {
diff --git a/include/clang/AST/CXXRecordDeclDefinitionBits.def b/include/clang/AST/CXXRecordDeclDefinitionBits.def
new file mode 100644
index 000000000000..bd4d8247aeca
--- /dev/null
+++ b/include/clang/AST/CXXRecordDeclDefinitionBits.def
@@ -0,0 +1,236 @@
+//===-- CXXRecordDeclDefinitionBits.def - Class definition bits -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file enumerates the various bitfields that we want to store on C++ class
+// definitions.
+//
+//===----------------------------------------------------------------------===//
+//
+/// @file CXXRecordDeclDefinitionBits.def
+///
+/// In this file, each of the bitfields representing data about a C++ class
+/// results in an expansion of the FIELD macro, which should be defined before
+/// including this file.
+///
+/// The macro have three operands:
+///
+/// Name: The name of the field, as a member of CXXRecordDecl::DefinitionData.
+///
+/// BitWidth: The width of the field in bits.
+///
+/// MergePolicy: How to behave when the value of the field is different in
+/// multiple translation units, one of:
+/// NO_MERGE: It is an ODR violation if the fields do not match.
+/// MERGE_OR: Merge the fields by ORing them together.
+
+#ifndef FIELD
+#error define FIELD before including this file
+#endif
+
+/// True if this class has any user-declared constructors.
+FIELD(UserDeclaredConstructor, 1, NO_MERGE)
+
+/// The user-declared special members which this class has.
+FIELD(UserDeclaredSpecialMembers, 6, NO_MERGE)
+
+/// True when this class is an aggregate.
+FIELD(Aggregate, 1, NO_MERGE)
+
+/// True when this class is a POD-type.
+FIELD(PlainOldData, 1, NO_MERGE)
+
+/// True when this class is empty for traits purposes, that is:
+/// * has no data members other than 0-width bit-fields and empty fields
+/// marked [[no_unique_address]]
+/// * has no virtual function/base, and
+/// * doesn't inherit from a non-empty class.
+/// Doesn't take union-ness into account.
+FIELD(Empty, 1, NO_MERGE)
+
+/// True when this class is polymorphic, i.e., has at
+/// least one virtual member or derives from a polymorphic class.
+FIELD(Polymorphic, 1, NO_MERGE)
+
+/// True when this class is abstract, i.e., has at least
+/// one pure virtual function, (that can come from a base class).
+FIELD(Abstract, 1, NO_MERGE)
+
+/// True when this class is standard-layout, per the applicable
+/// language rules (including DRs).
+FIELD(IsStandardLayout, 1, NO_MERGE)
+
+/// True when this class was standard-layout under the C++11
+/// definition.
+///
+/// C++11 [class]p7. A standard-layout class is a class that:
+/// * 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 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
+/// classes with non-static data members, and
+/// * has no base classes of the same type as the first non-static data
+/// member.
+FIELD(IsCXX11StandardLayout, 1, NO_MERGE)
+
+/// True when any base class has any declared non-static data
+/// members or bit-fields.
+/// This is a helper bit of state used to implement IsStandardLayout more
+/// efficiently.
+FIELD(HasBasesWithFields, 1, NO_MERGE)
+
+/// True when any base class has any declared non-static data
+/// members.
+/// This is a helper bit of state used to implement IsCXX11StandardLayout
+/// more efficiently.
+FIELD(HasBasesWithNonStaticDataMembers, 1, NO_MERGE)
+
+/// True when there are private non-static data members.
+FIELD(HasPrivateFields, 1, NO_MERGE)
+
+/// True when there are protected non-static data members.
+FIELD(HasProtectedFields, 1, NO_MERGE)
+
+/// True when there are private non-static data members.
+FIELD(HasPublicFields, 1, NO_MERGE)
+
+/// True if this class (or any subobject) has mutable fields.
+FIELD(HasMutableFields, 1, NO_MERGE)
+
+/// True if this class (or any nested anonymous struct or union)
+/// has variant members.
+FIELD(HasVariantMembers, 1, NO_MERGE)
+
+/// True if there no non-field members declared by the user.
+FIELD(HasOnlyCMembers, 1, NO_MERGE)
+
+/// True if any field has an in-class initializer, including those
+/// within anonymous unions or structs.
+FIELD(HasInClassInitializer, 1, NO_MERGE)
+
+/// True if any field is of reference type, and does not have an
+/// in-class initializer.
+///
+/// In this case, value-initialization of this class is illegal in C++98
+/// even if the class has a trivial default constructor.
+FIELD(HasUninitializedReferenceMember, 1, NO_MERGE)
+
+/// True if any non-mutable field whose type doesn't have a user-
+/// provided default ctor also doesn't have an in-class initializer.
+FIELD(HasUninitializedFields, 1, NO_MERGE)
+
+/// True if there are any member using-declarations that inherit
+/// constructors from a base class.
+FIELD(HasInheritedConstructor, 1, NO_MERGE)
+
+/// True if there are any member using-declarations named
+/// 'operator='.
+FIELD(HasInheritedAssignment, 1, NO_MERGE)
+
+/// These flags are \c true if a defaulted corresponding special
+/// member can't be fully analyzed without performing overload resolution.
+/// @{
+FIELD(NeedOverloadResolutionForCopyConstructor, 1, NO_MERGE)
+FIELD(NeedOverloadResolutionForMoveConstructor, 1, NO_MERGE)
+FIELD(NeedOverloadResolutionForMoveAssignment, 1, NO_MERGE)
+FIELD(NeedOverloadResolutionForDestructor, 1, NO_MERGE)
+/// @}
+
+/// These flags are \c true if an implicit defaulted corresponding
+/// special member would be defined as deleted.
+/// @{
+FIELD(DefaultedCopyConstructorIsDeleted, 1, NO_MERGE)
+FIELD(DefaultedMoveConstructorIsDeleted, 1, NO_MERGE)
+FIELD(DefaultedMoveAssignmentIsDeleted, 1, NO_MERGE)
+FIELD(DefaultedDestructorIsDeleted, 1, NO_MERGE)
+/// @}
+
+/// The trivial special members which this class has, per
+/// C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25,
+/// C++11 [class.dtor]p5, or would have if the member were not suppressed.
+///
+/// This excludes any user-declared but not user-provided special members
+/// which have been declared but not yet defined.
+FIELD(HasTrivialSpecialMembers, 6, MERGE_OR)
+
+/// These bits keep track of the triviality of special functions for the
+/// purpose of calls. Only the bits corresponding to SMF_CopyConstructor,
+/// SMF_MoveConstructor, and SMF_Destructor are meaningful here.
+FIELD(HasTrivialSpecialMembersForCall, 6, MERGE_OR)
+
+/// The declared special members of this class which are known to be
+/// non-trivial.
+///
+/// This excludes any user-declared but not user-provided special members
+/// which have been declared but not yet defined, and any implicit special
+/// members which have not yet been declared.
+FIELD(DeclaredNonTrivialSpecialMembers, 6, MERGE_OR)
+
+/// These bits keep track of the declared special members that are
+/// non-trivial for the purpose of calls.
+/// Only the bits corresponding to SMF_CopyConstructor,
+/// SMF_MoveConstructor, and SMF_Destructor are meaningful here.
+FIELD(DeclaredNonTrivialSpecialMembersForCall, 6, MERGE_OR)
+
+/// True when this class has a destructor with no semantic effect.
+FIELD(HasIrrelevantDestructor, 1, NO_MERGE)
+
+/// True when this class has at least one user-declared constexpr
+/// constructor which is neither the copy nor move constructor.
+FIELD(HasConstexprNonCopyMoveConstructor, 1, MERGE_OR)
+
+/// True if this class has a (possibly implicit) defaulted default
+/// constructor.
+FIELD(HasDefaultedDefaultConstructor, 1, MERGE_OR)
+
+/// True if a defaulted default constructor for this class would
+/// be constexpr.
+FIELD(DefaultedDefaultConstructorIsConstexpr, 1, NO_MERGE)
+
+/// True if this class has a constexpr default constructor.
+///
+/// This is true for either a user-declared constexpr default constructor
+/// or an implicitly declared constexpr default constructor.
+FIELD(HasConstexprDefaultConstructor, 1, MERGE_OR)
+
+/// True if a defaulted destructor for this class would be constexpr.
+FIELD(DefaultedDestructorIsConstexpr, 1, NO_MERGE)
+
+/// True when this class contains at least one non-static data
+/// member or base class of non-literal or volatile type.
+FIELD(HasNonLiteralTypeFieldsOrBases, 1, NO_MERGE)
+
+/// Whether we have a C++11 user-provided default constructor (not
+/// explicitly deleted or defaulted).
+FIELD(UserProvidedDefaultConstructor, 1, NO_MERGE)
+
+/// The special members which have been declared for this class,
+/// either by the user or implicitly.
+FIELD(DeclaredSpecialMembers, 6, MERGE_OR)
+
+/// Whether an implicit copy constructor could have a const-qualified
+/// parameter, for initializing virtual bases and for other subobjects.
+FIELD(ImplicitCopyConstructorCanHaveConstParamForVBase, 1, NO_MERGE)
+FIELD(ImplicitCopyConstructorCanHaveConstParamForNonVBase, 1, NO_MERGE)
+
+/// Whether an implicit copy assignment operator would have a
+/// const-qualified parameter.
+FIELD(ImplicitCopyAssignmentHasConstParam, 1, NO_MERGE)
+
+/// Whether any declared copy constructor has a const-qualified
+/// parameter.
+FIELD(HasDeclaredCopyConstructorWithConstParam, 1, MERGE_OR)
+
+/// Whether any declared copy assignment operator has either a
+/// const-qualified reference parameter or a non-reference parameter.
+FIELD(HasDeclaredCopyAssignmentWithConstParam, 1, MERGE_OR)
+
+#undef FIELD
diff --git a/include/clang/AST/CharUnits.h b/include/clang/AST/CharUnits.h
index 37f489c7708a..f14d3abf71e5 100644
--- a/include/clang/AST/CharUnits.h
+++ b/include/clang/AST/CharUnits.h
@@ -14,6 +14,7 @@
#define LLVM_CLANG_AST_CHARUNITS_H
#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/Support/Alignment.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/MathExtras.h"
@@ -177,6 +178,10 @@ namespace clang {
/// getQuantity - Get the raw integer representation of this quantity.
QuantityType getQuantity() const { return Quantity; }
+ /// getAsAlign - Returns Quantity as a valid llvm::Align,
+ /// Beware llvm::Align assumes power of two 8-bit bytes.
+ llvm::Align getAsAlign() const { return llvm::Align(Quantity); }
+
/// alignTo - Returns the next integer (mod 2**64) that is
/// greater than or equal to this quantity and is a multiple of \p Align.
/// Align must be non-zero.
diff --git a/include/clang/AST/CommentCommands.td b/include/clang/AST/CommentCommands.td
index 958ee032e71f..3b0d1603d407 100644
--- a/include/clang/AST/CommentCommands.td
+++ b/include/clang/AST/CommentCommands.td
@@ -139,6 +139,7 @@ def Post : BlockCommand<"post">;
def Pre : BlockCommand<"pre">;
def Remark : BlockCommand<"remark">;
def Remarks : BlockCommand<"remarks">;
+def Retval : BlockCommand<"retval">;
def Sa : BlockCommand<"sa">;
def See : BlockCommand<"see">;
def Since : BlockCommand<"since">;
diff --git a/include/clang/AST/CommentLexer.h b/include/clang/AST/CommentLexer.h
index 9ddbb7d31d99..138fdaca0ff6 100644
--- a/include/clang/AST/CommentLexer.h
+++ b/include/clang/AST/CommentLexer.h
@@ -352,8 +352,7 @@ public:
void lex(Token &T);
- StringRef getSpelling(const Token &Tok, const SourceManager &SourceMgr,
- bool *Invalid = nullptr) const;
+ StringRef getSpelling(const Token &Tok, const SourceManager &SourceMgr) const;
};
} // end namespace comments
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 02742801f37c..ce674e09c44d 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -310,6 +310,14 @@ public:
void printQualifiedName(raw_ostream &OS) const;
void printQualifiedName(raw_ostream &OS, const PrintingPolicy &Policy) const;
+ /// Print only the nested name specifier part of a fully-qualified name,
+ /// including the '::' at the end. E.g.
+ /// when `printQualifiedName(D)` prints "A::B::i",
+ /// this function prints "A::B::".
+ void printNestedNameSpecifier(raw_ostream &OS) const;
+ void printNestedNameSpecifier(raw_ostream &OS,
+ const PrintingPolicy &Policy) const;
+
// FIXME: Remove string version.
std::string getQualifiedNameAsString() const;
@@ -800,12 +808,19 @@ struct EvaluatedStmt {
/// valid if CheckedICE is true.
bool IsICE : 1;
+ /// Whether this variable is known to have constant destruction. That is,
+ /// whether running the destructor on the initial value is a side-effect
+ /// (and doesn't inspect any state that might have changed during program
+ /// execution). This is currently only computed if the destructor is
+ /// non-trivial.
+ bool HasConstantDestruction : 1;
+
Stmt *Value;
APValue Evaluated;
- EvaluatedStmt() : WasEvaluated(false), IsEvaluating(false), CheckedICE(false),
- CheckingICE(false), IsICE(false) {}
-
+ EvaluatedStmt()
+ : WasEvaluated(false), IsEvaluating(false), CheckedICE(false),
+ CheckingICE(false), IsICE(false), HasConstantDestruction(false) {}
};
/// Represents a variable declaration or definition.
@@ -1226,6 +1241,14 @@ public:
void setInit(Expr *I);
+ /// Get the initializing declaration of this variable, if any. This is
+ /// usually the definition, except that for a static data member it can be
+ /// the in-class declaration.
+ VarDecl *getInitializingDeclaration();
+ const VarDecl *getInitializingDeclaration() const {
+ return const_cast<VarDecl *>(this)->getInitializingDeclaration();
+ }
+
/// Determine whether this variable's value might be usable in a
/// constant expression, according to the relevant language standard.
/// This only checks properties of the declaration, and does not check
@@ -1251,6 +1274,14 @@ public:
/// to untyped APValue if the value could not be evaluated.
APValue *getEvaluatedValue() const;
+ /// Evaluate the destruction of this variable to determine if it constitutes
+ /// constant destruction.
+ ///
+ /// \pre isInitICE()
+ /// \return \c true if this variable has constant destruction, \c false if
+ /// not.
+ bool evaluateDestruction(SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
+
/// Determines whether it is already known whether the
/// initializer is an integral constant expression or not.
bool isInitKnownICE() const;
@@ -1489,9 +1520,14 @@ public:
// has no definition within this source file.
bool isKnownToBeDefined() const;
- /// Do we need to emit an exit-time destructor for this variable?
+ /// Is destruction of this variable entirely suppressed? If so, the variable
+ /// need not have a usable destructor at all.
bool isNoDestroy(const ASTContext &) const;
+ /// Do we need to emit an exit-time destructor for this variable, and if so,
+ /// what kind?
+ QualType::DestructionKind needsDestruction(const ASTContext &Ctx) const;
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; }
@@ -4078,13 +4114,9 @@ public:
void setCaptures(ASTContext &Context, ArrayRef<Capture> Captures,
bool CapturesCXXThis);
- unsigned getBlockManglingNumber() const {
- return ManglingNumber;
- }
+ unsigned getBlockManglingNumber() const { return ManglingNumber; }
- Decl *getBlockManglingContextDecl() const {
- return ManglingContextDecl;
- }
+ Decl *getBlockManglingContextDecl() const { return ManglingContextDecl; }
void setBlockMangling(unsigned Number, Decl *Ctx) {
ManglingNumber = Number;
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index d64d0cb425db..01c2f1809771 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -959,7 +959,7 @@ public:
/// as this declaration, or NULL if there is no previous declaration.
Decl *getPreviousDecl() { return getPreviousDeclImpl(); }
- /// Retrieve the most recent declaration that declares the same entity
+ /// Retrieve the previous 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();
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 7add83f89624..66212f72b787 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -42,6 +42,7 @@
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/iterator_range.h"
+#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
@@ -73,52 +74,6 @@ class TemplateDecl;
class TemplateParameterList;
class UsingDecl;
-/// Represents any kind of function declaration, whether it is a
-/// concrete function or a function template.
-class AnyFunctionDecl {
- NamedDecl *Function;
-
- AnyFunctionDecl(NamedDecl *ND) : Function(ND) {}
-
-public:
- AnyFunctionDecl(FunctionDecl *FD) : Function(FD) {}
- AnyFunctionDecl(FunctionTemplateDecl *FTD);
-
- /// Implicily converts any function or function template into a
- /// named declaration.
- operator NamedDecl *() const { return Function; }
-
- /// Retrieve the underlying function or function template.
- NamedDecl *get() const { return Function; }
-
- static AnyFunctionDecl getFromNamedDecl(NamedDecl *ND) {
- return AnyFunctionDecl(ND);
- }
-};
-
-} // namespace clang
-
-namespace llvm {
-
- // Provide PointerLikeTypeTraits for non-cvr pointers.
- template<>
- struct PointerLikeTypeTraits< ::clang::AnyFunctionDecl> {
- static void *getAsVoidPointer(::clang::AnyFunctionDecl F) {
- return F.get();
- }
-
- static ::clang::AnyFunctionDecl getFromVoidPointer(void *P) {
- return ::clang::AnyFunctionDecl::getFromNamedDecl(
- static_cast< ::clang::NamedDecl*>(P));
- }
-
- enum { NumLowBitsAvailable = 2 };
- };
-
-} // namespace llvm
-
-namespace clang {
-
/// Represents an access specifier followed by colon ':'.
///
/// An objects of this class represents sugar for the syntactic occurrence
@@ -322,207 +277,9 @@ class CXXRecordDecl : public RecordDecl {
};
struct DefinitionData {
- /// True if this class has any user-declared constructors.
- unsigned UserDeclaredConstructor : 1;
-
- /// The user-declared special members which this class has.
- unsigned UserDeclaredSpecialMembers : 6;
-
- /// True when this class is an aggregate.
- unsigned Aggregate : 1;
-
- /// True when this class is a POD-type.
- unsigned PlainOldData : 1;
-
- /// True when this class is empty for traits purposes, that is:
- /// * has no data members other than 0-width bit-fields and empty fields
- /// marked [[no_unique_address]]
- /// * has no virtual function/base, and
- /// * doesn't inherit from a non-empty class.
- /// Doesn't take union-ness into account.
- unsigned Empty : 1;
-
- /// True when this class is polymorphic, i.e., has at
- /// least one virtual member or derives from a polymorphic class.
- unsigned Polymorphic : 1;
-
- /// True when this class is abstract, i.e., has at least
- /// one pure virtual function, (that can come from a base class).
- unsigned Abstract : 1;
-
- /// True when this class is standard-layout, per the applicable
- /// language rules (including DRs).
- unsigned IsStandardLayout : 1;
-
- /// True when this class was standard-layout under the C++11
- /// definition.
- ///
- /// C++11 [class]p7. A standard-layout class is a class that:
- /// * 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 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
- /// classes with non-static data members, and
- /// * has no base classes of the same type as the first non-static data
- /// member.
- unsigned IsCXX11StandardLayout : 1;
-
- /// True when any base class has any declared non-static data
- /// members or bit-fields.
- /// This is a helper bit of state used to implement IsStandardLayout more
- /// efficiently.
- unsigned HasBasesWithFields : 1;
-
- /// True when any base class has any declared non-static data
- /// members.
- /// This is a helper bit of state used to implement IsCXX11StandardLayout
- /// more efficiently.
- unsigned HasBasesWithNonStaticDataMembers : 1;
-
- /// True when there are private non-static data members.
- unsigned HasPrivateFields : 1;
-
- /// True when there are protected non-static data members.
- unsigned HasProtectedFields : 1;
-
- /// True when there are private non-static data members.
- unsigned HasPublicFields : 1;
-
- /// True if this class (or any subobject) has mutable fields.
- unsigned HasMutableFields : 1;
-
- /// True if this class (or any nested anonymous struct or union)
- /// has variant members.
- unsigned HasVariantMembers : 1;
-
- /// True if there no non-field members declared by the user.
- unsigned HasOnlyCMembers : 1;
-
- /// True if any field has an in-class initializer, including those
- /// within anonymous unions or structs.
- unsigned HasInClassInitializer : 1;
-
- /// True if any field is of reference type, and does not have an
- /// in-class initializer.
- ///
- /// In this case, value-initialization of this class is illegal in C++98
- /// even if the class has a trivial default constructor.
- unsigned HasUninitializedReferenceMember : 1;
-
- /// True if any non-mutable field whose type doesn't have a user-
- /// provided default ctor also doesn't have an in-class initializer.
- unsigned HasUninitializedFields : 1;
-
- /// True if there are any member using-declarations that inherit
- /// constructors from a base class.
- unsigned HasInheritedConstructor : 1;
-
- /// True if there are any member using-declarations named
- /// 'operator='.
- unsigned HasInheritedAssignment : 1;
-
- /// These flags are \c true if a defaulted corresponding special
- /// member can't be fully analyzed without performing overload resolution.
- /// @{
- unsigned NeedOverloadResolutionForCopyConstructor : 1;
- unsigned NeedOverloadResolutionForMoveConstructor : 1;
- unsigned NeedOverloadResolutionForMoveAssignment : 1;
- unsigned NeedOverloadResolutionForDestructor : 1;
- /// @}
-
- /// These flags are \c true if an implicit defaulted corresponding
- /// special member would be defined as deleted.
- /// @{
- unsigned DefaultedCopyConstructorIsDeleted : 1;
- unsigned DefaultedMoveConstructorIsDeleted : 1;
- unsigned DefaultedMoveAssignmentIsDeleted : 1;
- unsigned DefaultedDestructorIsDeleted : 1;
- /// @}
-
- /// The trivial special members which this class has, per
- /// C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25,
- /// C++11 [class.dtor]p5, or would have if the member were not suppressed.
- ///
- /// This excludes any user-declared but not user-provided special members
- /// which have been declared but not yet defined.
- unsigned HasTrivialSpecialMembers : 6;
-
- /// These bits keep track of the triviality of special functions for the
- /// purpose of calls. Only the bits corresponding to SMF_CopyConstructor,
- /// SMF_MoveConstructor, and SMF_Destructor are meaningful here.
- unsigned HasTrivialSpecialMembersForCall : 6;
-
- /// The declared special members of this class which are known to be
- /// non-trivial.
- ///
- /// This excludes any user-declared but not user-provided special members
- /// which have been declared but not yet defined, and any implicit special
- /// members which have not yet been declared.
- unsigned DeclaredNonTrivialSpecialMembers : 6;
-
- /// These bits keep track of the declared special members that are
- /// non-trivial for the purpose of calls.
- /// Only the bits corresponding to SMF_CopyConstructor,
- /// SMF_MoveConstructor, and SMF_Destructor are meaningful here.
- unsigned DeclaredNonTrivialSpecialMembersForCall : 6;
-
- /// True when this class has a destructor with no semantic effect.
- unsigned HasIrrelevantDestructor : 1;
-
- /// True when this class has at least one user-declared constexpr
- /// constructor which is neither the copy nor move constructor.
- unsigned HasConstexprNonCopyMoveConstructor : 1;
-
- /// True if this class has a (possibly implicit) defaulted default
- /// constructor.
- unsigned HasDefaultedDefaultConstructor : 1;
-
- /// True if a defaulted default constructor for this class would
- /// be constexpr.
- unsigned DefaultedDefaultConstructorIsConstexpr : 1;
-
- /// True if this class has a constexpr default constructor.
- ///
- /// This is true for either a user-declared constexpr default constructor
- /// or an implicitly declared constexpr default constructor.
- unsigned HasConstexprDefaultConstructor : 1;
-
- /// True when this class contains at least one non-static data
- /// member or base class of non-literal or volatile type.
- unsigned HasNonLiteralTypeFieldsOrBases : 1;
-
- /// True when visible conversion functions are already computed
- /// and are available.
- unsigned ComputedVisibleConversions : 1;
-
- /// Whether we have a C++11 user-provided default constructor (not
- /// explicitly deleted or defaulted).
- unsigned UserProvidedDefaultConstructor : 1;
-
- /// The special members which have been declared for this class,
- /// either by the user or implicitly.
- unsigned DeclaredSpecialMembers : 6;
-
- /// Whether an implicit copy constructor could have a const-qualified
- /// parameter, for initializing virtual bases and for other subobjects.
- unsigned ImplicitCopyConstructorCanHaveConstParamForVBase : 1;
- unsigned ImplicitCopyConstructorCanHaveConstParamForNonVBase : 1;
-
- /// Whether an implicit copy assignment operator would have a
- /// const-qualified parameter.
- unsigned ImplicitCopyAssignmentHasConstParam : 1;
-
- /// Whether any declared copy constructor has a const-qualified
- /// parameter.
- unsigned HasDeclaredCopyConstructorWithConstParam : 1;
-
- /// Whether any declared copy assignment operator has either a
- /// const-qualified reference parameter or a non-reference parameter.
- unsigned HasDeclaredCopyAssignmentWithConstParam : 1;
+ #define FIELD(Name, Width, Merge) \
+ unsigned Name : Width;
+ #include "CXXRecordDeclDefinitionBits.def"
/// Whether this class describes a C++ lambda.
unsigned IsLambda : 1;
@@ -530,6 +287,10 @@ class CXXRecordDecl : public RecordDecl {
/// Whether we are currently parsing base specifiers.
unsigned IsParsingBaseSpecifiers : 1;
+ /// True when visible conversion functions are already computed
+ /// and are available.
+ unsigned ComputedVisibleConversions : 1;
+
unsigned HasODRHash : 1;
/// A hash of parts of the class to help in ODR checking.
@@ -628,9 +389,12 @@ class CXXRecordDecl : public RecordDecl {
/// The number of explicit captures in this lambda.
unsigned NumExplicitCaptures : 13;
+ /// Has known `internal` linkage.
+ unsigned HasKnownInternalLinkage : 1;
+
/// The number used to indicate this lambda expression for name
/// mangling in the Itanium C++ ABI.
- unsigned ManglingNumber = 0;
+ unsigned ManglingNumber : 31;
/// The declaration that provides context for this lambda, if the
/// actual DeclContext does not suffice. This is used for lambdas that
@@ -645,12 +409,12 @@ class CXXRecordDecl : public RecordDecl {
/// The type of the call method.
TypeSourceInfo *MethodTyInfo;
- LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info,
- bool Dependent, bool IsGeneric,
- LambdaCaptureDefault CaptureDefault)
- : DefinitionData(D), Dependent(Dependent), IsGenericLambda(IsGeneric),
- CaptureDefault(CaptureDefault), NumCaptures(0), NumExplicitCaptures(0),
- MethodTyInfo(Info) {
+ LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info, bool Dependent,
+ bool IsGeneric, LambdaCaptureDefault CaptureDefault)
+ : DefinitionData(D), Dependent(Dependent), IsGenericLambda(IsGeneric),
+ CaptureDefault(CaptureDefault), NumCaptures(0),
+ NumExplicitCaptures(0), HasKnownInternalLinkage(0), ManglingNumber(0),
+ MethodTyInfo(Info) {
IsLambda = true;
// C++1z [expr.prim.lambda]p4:
@@ -1214,6 +978,10 @@ public:
/// if this is a closure type.
CXXMethodDecl *getLambdaCallOperator() const;
+ /// Retrieve the dependent lambda call operator of the closure type
+ /// if this is a templated closure type.
+ FunctionTemplateDecl *getDependentLambdaCallOperator() const;
+
/// Retrieve the lambda static invoker, the address of which
/// is returned by the conversion operator, and the body of which
/// is forwarded to the lambda call operator.
@@ -1398,7 +1166,8 @@ public:
/// would be constexpr.
bool defaultedDefaultConstructorIsConstexpr() const {
return data().DefaultedDefaultConstructorIsConstexpr &&
- (!isUnion() || hasInClassInitializer() || !hasVariantMembers());
+ (!isUnion() || hasInClassInitializer() || !hasVariantMembers() ||
+ getASTContext().getLangOpts().CPlusPlus2a);
}
/// Determine whether this class has a constexpr default constructor.
@@ -1486,6 +1255,16 @@ public:
!(data().HasTrivialSpecialMembers & SMF_MoveAssignment));
}
+ /// Determine whether a defaulted default constructor for this class
+ /// would be constexpr.
+ bool defaultedDestructorIsConstexpr() const {
+ return data().DefaultedDestructorIsConstexpr &&
+ getASTContext().getLangOpts().CPlusPlus2a;
+ }
+
+ /// Determine whether this class has a constexpr destructor.
+ bool hasConstexprDestructor() const;
+
/// Determine whether this class has a trivial destructor
/// (C++ [class.dtor]p3)
bool hasTrivialDestructor() const {
@@ -1577,8 +1356,10 @@ public:
///
/// Only in C++17 and beyond, are lambdas literal types.
bool isLiteral() const {
- return hasTrivialDestructor() &&
- (!isLambda() || getASTContext().getLangOpts().CPlusPlus17) &&
+ ASTContext &Ctx = getASTContext();
+ return (Ctx.getLangOpts().CPlusPlus2a ? hasConstexprDestructor()
+ : hasTrivialDestructor()) &&
+ (!isLambda() || Ctx.getLangOpts().CPlusPlus17) &&
!hasNonLiteralTypeFieldsOrBases() &&
(isAggregate() || isLambda() ||
hasConstexprNonCopyMoveConstructor() ||
@@ -1927,6 +1708,13 @@ public:
return getLambdaData().ManglingNumber;
}
+ /// The lambda is known to has internal linkage no matter whether it has name
+ /// mangling number.
+ bool hasKnownLambdaInternalLinkage() const {
+ assert(isLambda() && "Not a lambda closure type!");
+ return getLambdaData().HasKnownInternalLinkage;
+ }
+
/// Retrieve the declaration that provides additional context for a
/// lambda, when the normal declaration context is not specific enough.
///
@@ -1940,9 +1728,12 @@ public:
/// Set the mangling number and context declaration for a lambda
/// class.
- void setLambdaMangling(unsigned ManglingNumber, Decl *ContextDecl) {
+ void setLambdaMangling(unsigned ManglingNumber, Decl *ContextDecl,
+ bool HasKnownInternalLinkage = false) {
+ assert(isLambda() && "Not a lambda closure type!");
getLambdaData().ManglingNumber = ManglingNumber;
getLambdaData().ContextDecl = ContextDecl;
+ getLambdaData().HasKnownInternalLinkage = HasKnownInternalLinkage;
}
/// Returns the inheritance model used for this record.
@@ -2265,7 +2056,7 @@ public:
const CXXRecordDecl *Decl);
Qualifiers getMethodQualifiers() const {
- return getType()->getAs<FunctionProtoType>()->getMethodQuals();
+ return getType()->castAs<FunctionProtoType>()->getMethodQuals();
}
/// Retrieve the ref-qualifier associated with this method.
@@ -2280,7 +2071,7 @@ public:
/// };
/// @endcode
RefQualifierKind getRefQualifier() const {
- return getType()->getAs<FunctionProtoType>()->getRefQualifier();
+ return getType()->castAs<FunctionProtoType>()->getRefQualifier();
}
bool hasInlineBody() const;
@@ -2600,9 +2391,9 @@ class CXXConstructorDecl final
ExplicitSpecifier getExplicitSpecifierInternal() const {
if (CXXConstructorDeclBits.HasTrailingExplicitSpecifier)
- return *getCanonicalDecl()->getTrailingObjects<ExplicitSpecifier>();
+ return *getTrailingObjects<ExplicitSpecifier>();
return ExplicitSpecifier(
- nullptr, getCanonicalDecl()->CXXConstructorDeclBits.IsSimpleExplicit
+ nullptr, CXXConstructorDeclBits.IsSimpleExplicit
? ExplicitSpecKind::ResolvedTrue
: ExplicitSpecKind::ResolvedFalse);
}
@@ -2643,10 +2434,10 @@ public:
InheritedConstructor Inherited = InheritedConstructor());
ExplicitSpecifier getExplicitSpecifier() {
- return getExplicitSpecifierInternal();
+ return getCanonicalDecl()->getExplicitSpecifierInternal();
}
const ExplicitSpecifier getExplicitSpecifier() const {
- return getExplicitSpecifierInternal();
+ return getCanonicalDecl()->getExplicitSpecifierInternal();
}
/// Return true if the declartion is already resolved to be explicit.
@@ -2847,9 +2638,9 @@ class CXXDestructorDecl : public CXXMethodDecl {
CXXDestructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, bool isInline,
- bool isImplicitlyDeclared)
+ bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind)
: CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo,
- SC_None, isInline, CSK_unspecified, SourceLocation()) {
+ SC_None, isInline, ConstexprKind, SourceLocation()) {
setImplicit(isImplicitlyDeclared);
}
@@ -2859,9 +2650,9 @@ public:
static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
- QualType T, TypeSourceInfo* TInfo,
- bool isInline,
- bool isImplicitlyDeclared);
+ QualType T, TypeSourceInfo *TInfo,
+ bool isInline, bool isImplicitlyDeclared,
+ ConstexprSpecKind ConstexprKind);
static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID);
void setOperatorDelete(FunctionDecl *OD, Expr *ThisArg);
@@ -2934,7 +2725,7 @@ public:
/// Returns the type that this conversion function is converting to.
QualType getConversionType() const {
- return getType()->getAs<FunctionType>()->getReturnType();
+ return getType()->castAs<FunctionType>()->getReturnType();
}
/// Determine whether this conversion function is a conversion from
@@ -2971,8 +2762,10 @@ public:
/// ensure a stable ABI for this, we choose the DW_LANG_ encodings
/// from the dwarf standard.
enum LanguageIDs {
- lang_c = /* DW_LANG_C */ 0x0002,
- lang_cxx = /* DW_LANG_C_plus_plus */ 0x0004
+ lang_c = llvm::dwarf::DW_LANG_C,
+ lang_cxx = llvm::dwarf::DW_LANG_C_plus_plus,
+ lang_cxx_11 = llvm::dwarf::DW_LANG_C_plus_plus_11,
+ lang_cxx_14 = llvm::dwarf::DW_LANG_C_plus_plus_14
};
private:
@@ -3469,12 +3262,6 @@ public:
return IsVirtual;
}
- /// Get the constructor or constructor template in the derived class
- /// correspnding to this using shadow declaration, if it has been implicitly
- /// declared already.
- CXXConstructorDecl *getConstructor() const;
- void setConstructor(NamedDecl *Ctor);
-
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ConstructorUsingShadow; }
};
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 235b31c1c312..ec14adc7de97 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -168,6 +168,16 @@ public:
return HasRequiresClause ? *getTrailingObjects<Expr *>() : nullptr;
}
+ /// \brief All associated constraints derived from this template parameter
+ /// list, including the requires clause and any constraints derived from
+ /// constrained-parameters.
+ ///
+ /// The constraints in the resulting list are to be treated as if in a
+ /// conjunction ("and").
+ void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const;
+
+ bool hasAssociatedConstraints() const;
+
SourceLocation getTemplateLoc() const { return TemplateLoc; }
SourceLocation getLAngleLoc() const { return LAngleLoc; }
SourceLocation getRAngleLoc() const { return RAngleLoc; }
@@ -369,33 +379,7 @@ public:
// Kinds of Templates
//===----------------------------------------------------------------------===//
-/// Stores the template parameter list and associated constraints for
-/// \c TemplateDecl objects that track associated constraints.
-class ConstrainedTemplateDeclInfo {
- friend TemplateDecl;
-
-public:
- ConstrainedTemplateDeclInfo() = default;
-
- TemplateParameterList *getTemplateParameters() const {
- return TemplateParams;
- }
-
- Expr *getAssociatedConstraints() const { return AssociatedConstraints; }
-
-protected:
- void setTemplateParameters(TemplateParameterList *TParams) {
- TemplateParams = TParams;
- }
-
- void setAssociatedConstraints(Expr *AC) { AssociatedConstraints = AC; }
-
- TemplateParameterList *TemplateParams = nullptr;
- Expr *AssociatedConstraints = nullptr;
-};
-
-
-/// The base class of all kinds of template declarations (e.g.,
+/// \brief The base class of all kinds of template declarations (e.g.,
/// class, function, etc.).
///
/// The TemplateDecl class stores the list of template parameters and a
@@ -404,54 +388,32 @@ class TemplateDecl : public NamedDecl {
void anchor() override;
protected:
+ // Construct a template decl with name, parameters, and templated element.
+ TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params, NamedDecl *Decl);
+
// Construct a template decl with the given name and parameters.
// Used when there is no templated element (e.g., for tt-params).
- TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC,
- SourceLocation L, DeclarationName Name,
- TemplateParameterList *Params)
- : NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr),
- TemplateParams(CTDI) {
- this->setTemplateParameters(Params);
- }
-
TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params)
- : TemplateDecl(nullptr, DK, DC, L, Name, Params) {}
-
- // Construct a template decl with name, parameters, and templated element.
- TemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK, DeclContext *DC,
- SourceLocation L, DeclarationName Name,
- TemplateParameterList *Params, NamedDecl *Decl)
- : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl),
- TemplateParams(CTDI) {
- this->setTemplateParameters(Params);
- }
-
- TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name,
- TemplateParameterList *Params, NamedDecl *Decl)
- : TemplateDecl(nullptr, DK, DC, L, Name, Params, Decl) {}
+ : TemplateDecl(DK, DC, L, Name, Params, nullptr) {}
public:
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
+
/// Get the list of template parameters
TemplateParameterList *getTemplateParameters() const {
- const auto *const CTDI =
- TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>();
- return CTDI ? CTDI->getTemplateParameters()
- : TemplateParams.get<TemplateParameterList *>();
+ return TemplateParams;
}
- /// Get the constraint-expression from the associated requires-clause (if any)
- const Expr *getRequiresClause() const {
- const TemplateParameterList *const TP = getTemplateParameters();
- return TP ? TP->getRequiresClause() : nullptr;
- }
+ /// \brief Get the total constraint-expression associated with this template,
+ /// including constraint-expressions derived from the requires-clause,
+ /// trailing requires-clause (for functions and methods) and constrained
+ /// template parameters.
+ void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const;
- Expr *getAssociatedConstraints() const {
- const auto *const C = cast<TemplateDecl>(getCanonicalDecl());
- const auto *const CTDI =
- C->TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>();
- return CTDI ? CTDI->getAssociatedConstraints() : nullptr;
- }
+ bool hasAssociatedConstraints() const;
/// Get the underlying, templated declaration.
NamedDecl *getTemplatedDecl() const { return TemplatedDecl; }
@@ -470,29 +432,10 @@ public:
protected:
NamedDecl *TemplatedDecl;
-
- /// The template parameter list and optional requires-clause
- /// associated with this declaration; alternatively, a
- /// \c ConstrainedTemplateDeclInfo if the associated constraints of the
- /// template are being tracked by this particular declaration.
- llvm::PointerUnion<TemplateParameterList *,
- ConstrainedTemplateDeclInfo *>
- TemplateParams;
+ TemplateParameterList *TemplateParams;
void setTemplateParameters(TemplateParameterList *TParams) {
- if (auto *const CTDI =
- TemplateParams.dyn_cast<ConstrainedTemplateDeclInfo *>()) {
- CTDI->setTemplateParameters(TParams);
- } else {
- TemplateParams = TParams;
- }
- }
-
- void setAssociatedConstraints(Expr *AC) {
- assert(isCanonicalDecl() &&
- "Attaching associated constraints to non-canonical Decl");
- TemplateParams.get<ConstrainedTemplateDeclInfo *>()
- ->setAssociatedConstraints(AC);
+ TemplateParams = TParams;
}
public:
@@ -889,17 +832,10 @@ protected:
virtual CommonBase *newCommon(ASTContext &C) const = 0;
// Construct a template decl with name, parameters, and templated element.
- RedeclarableTemplateDecl(ConstrainedTemplateDeclInfo *CTDI, Kind DK,
- ASTContext &C, DeclContext *DC, SourceLocation L,
- DeclarationName Name, TemplateParameterList *Params,
- NamedDecl *Decl)
- : TemplateDecl(CTDI, DK, DC, L, Name, Params, Decl), redeclarable_base(C)
- {}
-
RedeclarableTemplateDecl(Kind DK, ASTContext &C, DeclContext *DC,
SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
- : RedeclarableTemplateDecl(nullptr, DK, C, DC, L, Name, Params, Decl) {}
+ : TemplateDecl(DK, DC, L, Name, Params, Decl), redeclarable_base(C) {}
public:
friend class ASTDeclReader;
@@ -2026,6 +1962,20 @@ public:
return TemplateParams;
}
+ /// \brief All associated constraints of this partial specialization,
+ /// including the requires clause and any constraints derived from
+ /// constrained-parameters.
+ ///
+ /// The constraints in the resulting list are to be treated as if in a
+ /// conjunction ("and").
+ void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
+ TemplateParams->getAssociatedConstraints(AC);
+ }
+
+ bool hasAssociatedConstraints() const {
+ return TemplateParams->hasAssociatedConstraints();
+ }
+
/// Get the template arguments as written.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
return ArgsAsWritten;
@@ -2145,16 +2095,10 @@ protected:
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &
getPartialSpecializations();
- ClassTemplateDecl(ConstrainedTemplateDeclInfo *CTDI, ASTContext &C,
- DeclContext *DC, SourceLocation L, DeclarationName Name,
- TemplateParameterList *Params, NamedDecl *Decl)
- : RedeclarableTemplateDecl(CTDI, ClassTemplate, C, DC, L, Name, Params,
- Decl) {}
-
ClassTemplateDecl(ASTContext &C, DeclContext *DC, SourceLocation L,
DeclarationName Name, TemplateParameterList *Params,
NamedDecl *Decl)
- : ClassTemplateDecl(nullptr, C, DC, L, Name, Params, Decl) {}
+ : RedeclarableTemplateDecl(ClassTemplate, C, DC, L, Name, Params, Decl) {}
CommonBase *newCommon(ASTContext &C) const override;
@@ -2180,14 +2124,12 @@ public:
return getTemplatedDecl()->isThisDeclarationADefinition();
}
- // FIXME: remove default argument for AssociatedConstraints
- /// Create a class template node.
+ /// \brief Create a class template node.
static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
- NamedDecl *Decl,
- Expr *AssociatedConstraints = nullptr);
+ NamedDecl *Decl);
/// Create an empty class template node.
static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -2527,10 +2469,6 @@ public:
}
};
-/// Implementation of inline functions that require the template declarations
-inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
- : Function(FTD) {}
-
/// Represents a variable template specialization, which refers to
/// a variable template with a given set of template arguments.
///
@@ -2866,7 +2804,21 @@ public:
return ArgsAsWritten;
}
- /// Retrieve the member variable template partial specialization from
+ /// \brief All associated constraints of this partial specialization,
+ /// including the requires clause and any constraints derived from
+ /// constrained-parameters.
+ ///
+ /// The constraints in the resulting list are to be treated as if in a
+ /// conjunction ("and").
+ void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
+ TemplateParams->getAssociatedConstraints(AC);
+ }
+
+ bool hasAssociatedConstraints() const {
+ return TemplateParams->hasAssociatedConstraints();
+ }
+
+ /// \brief Retrieve the member variable template partial specialization from
/// which this particular variable template partial specialization was
/// instantiated.
///
@@ -3095,11 +3047,9 @@ class ConceptDecl : public TemplateDecl, public Mergeable<ConceptDecl> {
protected:
Expr *ConstraintExpr;
- ConceptDecl(DeclContext *DC,
- SourceLocation L, DeclarationName Name,
- TemplateParameterList *Params,
- Expr *ConstraintExpr)
- : TemplateDecl(nullptr, Concept, DC, L, Name, Params),
+ ConceptDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params, Expr *ConstraintExpr)
+ : TemplateDecl(Concept, DC, L, Name, Params),
ConstraintExpr(ConstraintExpr) {};
public:
static ConceptDecl *Create(ASTContext &C, DeclContext *DC,
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index d44a815c8699..ffa7d4db96a4 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -906,6 +906,11 @@ public:
return skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
}
+ /// Checks that the two Expr's will refer to the same value as a comparison
+ /// operand. The caller must ensure that the values referenced by the Expr's
+ /// are not modified between E1 and E2 or the result my be invalid.
+ static bool isSameComparisonOperand(const Expr* E1, const Expr* E2);
+
static bool classof(const Stmt *T) {
return T->getStmtClass() >= firstExprConstant &&
T->getStmtClass() <= lastExprConstant;
@@ -2619,9 +2624,8 @@ public:
/// + sizeof(Stmt *) bytes of storage, aligned to alignof(CallExpr):
///
/// \code{.cpp}
- /// llvm::AlignedCharArray<alignof(CallExpr),
- /// sizeof(CallExpr) + sizeof(Stmt *)> Buffer;
- /// CallExpr *TheCall = CallExpr::CreateTemporary(Buffer.buffer, etc);
+ /// alignas(CallExpr) char Buffer[sizeof(CallExpr) + sizeof(Stmt *)];
+ /// CallExpr *TheCall = CallExpr::CreateTemporary(Buffer, etc);
/// \endcode
static CallExpr *CreateTemporary(void *Mem, Expr *Fn, QualType Ty,
ExprValueKind VK, SourceLocation RParenLoc,
@@ -4496,6 +4500,8 @@ public:
// Explicit InitListExpr's originate from source code (and have valid source
// locations). Implicit InitListExpr's are created by the semantic analyzer.
+ // FIXME: This is wrong; InitListExprs created by semantic analysis have
+ // valid source locations too!
bool isExplicit() const {
return LBraceLoc.isValid() && RBraceLoc.isValid();
}
@@ -4830,6 +4836,10 @@ public:
SourceLocation getEqualOrColonLoc() const { return EqualOrColonLoc; }
void setEqualOrColonLoc(SourceLocation L) { EqualOrColonLoc = L; }
+ /// Whether this designated initializer should result in direct-initialization
+ /// of the designated subobject (eg, '{.foo{1, 2, 3}}').
+ bool isDirectInit() const { return EqualOrColonLoc.isInvalid(); }
+
/// Determines whether this designated initializer used the
/// deprecated GNU syntax for designated initializers.
bool usesGNUSyntax() const { return GNUSyntax; }
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 28ed6cdfde14..2152e108c7cb 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -17,6 +17,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h"
#include "clang/AST/NestedNameSpecifier.h"
@@ -185,15 +186,20 @@ public:
static CXXMemberCallExpr *CreateEmpty(const ASTContext &Ctx, unsigned NumArgs,
EmptyShell Empty);
- /// Retrieves the implicit object argument for the member call.
+ /// Retrieve the implicit object argument for the member call.
///
/// For example, in "x.f(5)", this returns the sub-expression "x".
Expr *getImplicitObjectArgument() const;
- /// Retrieves the declaration of the called method.
+ /// Retrieve the type of the object argument.
+ ///
+ /// Note that this always returns a non-pointer type.
+ QualType getObjectType() const;
+
+ /// Retrieve the declaration of the called method.
CXXMethodDecl *getMethodDecl() const;
- /// Retrieves the CXXRecordDecl for the underlying type of
+ /// Retrieve the CXXRecordDecl for the underlying type of
/// the implicit object argument.
///
/// Note that this is may not be the same declaration as that of the class
@@ -248,6 +254,96 @@ public:
}
};
+/// A rewritten comparison expression that was originally written using
+/// operator syntax.
+///
+/// In C++20, the following rewrites are performed:
+/// - <tt>a == b</tt> -> <tt>b == a</tt>
+/// - <tt>a != b</tt> -> <tt>!(a == b)</tt>
+/// - <tt>a != b</tt> -> <tt>!(b == a)</tt>
+/// - For \c \@ in \c <, \c <=, \c >, \c >=, \c <=>:
+/// - <tt>a @ b</tt> -> <tt>(a <=> b) @ 0</tt>
+/// - <tt>a @ b</tt> -> <tt>0 @ (b <=> a)</tt>
+///
+/// This expression provides access to both the original syntax and the
+/// rewritten expression.
+///
+/// Note that the rewritten calls to \c ==, \c <=>, and \c \@ are typically
+/// \c CXXOperatorCallExprs, but could theoretically be \c BinaryOperators.
+class CXXRewrittenBinaryOperator : public Expr {
+ friend class ASTStmtReader;
+
+ /// The rewritten semantic form.
+ Stmt *SemanticForm;
+
+public:
+ CXXRewrittenBinaryOperator(Expr *SemanticForm, bool IsReversed)
+ : Expr(CXXRewrittenBinaryOperatorClass, SemanticForm->getType(),
+ SemanticForm->getValueKind(), SemanticForm->getObjectKind(),
+ SemanticForm->isTypeDependent(), SemanticForm->isValueDependent(),
+ SemanticForm->isInstantiationDependent(),
+ SemanticForm->containsUnexpandedParameterPack()),
+ SemanticForm(SemanticForm) {
+ CXXRewrittenBinaryOperatorBits.IsReversed = IsReversed;
+ }
+ CXXRewrittenBinaryOperator(EmptyShell Empty)
+ : Expr(CXXRewrittenBinaryOperatorClass, Empty), SemanticForm() {}
+
+ /// Get an equivalent semantic form for this expression.
+ Expr *getSemanticForm() { return cast<Expr>(SemanticForm); }
+ const Expr *getSemanticForm() const { return cast<Expr>(SemanticForm); }
+
+ struct DecomposedForm {
+ /// The original opcode, prior to rewriting.
+ BinaryOperatorKind Opcode;
+ /// The original left-hand side.
+ const Expr *LHS;
+ /// The original right-hand side.
+ const Expr *RHS;
+ /// The inner \c == or \c <=> operator expression.
+ const Expr *InnerBinOp;
+ };
+
+ /// Decompose this operator into its syntactic form.
+ DecomposedForm getDecomposedForm() const LLVM_READONLY;
+
+ /// Determine whether this expression was rewritten in reverse form.
+ bool isReversed() const { return CXXRewrittenBinaryOperatorBits.IsReversed; }
+
+ BinaryOperatorKind getOperator() const { return getDecomposedForm().Opcode; }
+ const Expr *getLHS() const { return getDecomposedForm().LHS; }
+ const Expr *getRHS() const { return getDecomposedForm().RHS; }
+
+ SourceLocation getOperatorLoc() const LLVM_READONLY {
+ return getDecomposedForm().InnerBinOp->getExprLoc();
+ }
+ SourceLocation getExprLoc() const LLVM_READONLY { return getOperatorLoc(); }
+
+ /// Compute the begin and end locations from the decomposed form.
+ /// The locations of the semantic form are not reliable if this is
+ /// a reversed expression.
+ //@{
+ SourceLocation getBeginLoc() const LLVM_READONLY {
+ return getDecomposedForm().LHS->getBeginLoc();
+ }
+ SourceLocation getEndLoc() const LLVM_READONLY {
+ return getDecomposedForm().RHS->getEndLoc();
+ }
+ SourceRange getSourceRange() const LLVM_READONLY {
+ DecomposedForm DF = getDecomposedForm();
+ return SourceRange(DF.LHS->getBeginLoc(), DF.RHS->getEndLoc());
+ }
+ //@}
+
+ child_range children() {
+ return child_range(&SemanticForm, &SemanticForm + 1);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXRewrittenBinaryOperatorClass;
+ }
+};
+
/// Abstract class common to all of the C++ "named"/"keyword" casts.
///
/// This abstract class is inherited by all of the classes
@@ -1902,6 +1998,10 @@ public:
/// lambda expression.
CXXMethodDecl *getCallOperator() const;
+ /// Retrieve the function template call operator associated with this
+ /// lambda expression.
+ FunctionTemplateDecl *getDependentCallOperator() const;
+
/// If this is a generic lambda expression, retrieve the template
/// parameter list associated with it, or else return null.
TemplateParameterList *getTemplateParameterList() const;
@@ -2091,8 +2191,7 @@ public:
bool IsParenTypeId);
QualType getAllocatedType() const {
- assert(getType()->isPointerType());
- return getType()->getAs<PointerType>()->getPointeeType();
+ return getType()->castAs<PointerType>()->getPointeeType();
}
TypeSourceInfo *getAllocatedTypeSourceInfo() const {
@@ -2270,8 +2369,8 @@ public:
CXXDeleteExpr(QualType Ty, bool GlobalDelete, bool ArrayForm,
bool ArrayFormAsWritten, bool UsualArrayDeleteWantsSize,
FunctionDecl *OperatorDelete, Expr *Arg, SourceLocation Loc)
- : Expr(CXXDeleteExprClass, Ty, VK_RValue, OK_Ordinary, false, false,
- Arg->isInstantiationDependent(),
+ : Expr(CXXDeleteExprClass, Ty, VK_RValue, OK_Ordinary, false,
+ Arg->isValueDependent(), Arg->isInstantiationDependent(),
Arg->containsUnexpandedParameterPack()),
OperatorDelete(OperatorDelete), Argument(Arg) {
CXXDeleteExprBits.GlobalDelete = GlobalDelete;
@@ -4335,9 +4434,6 @@ private:
};
llvm::PointerUnion<Stmt *, ExtraState *> State;
- void initializeExtraState(const ValueDecl *ExtendedBy,
- unsigned ManglingNumber);
-
public:
MaterializeTemporaryExpr(QualType T, Expr *Temporary,
bool BoundToLvalueReference)
@@ -4745,6 +4841,125 @@ public:
}
};
+/// \brief Represents the specialization of a concept - evaluates to a prvalue
+/// of type bool.
+///
+/// According to C++2a [expr.prim.id]p3 an id-expression that denotes the
+/// specialization of a concept results in a prvalue of type bool.
+class ConceptSpecializationExpr final : public Expr,
+ private llvm::TrailingObjects<ConceptSpecializationExpr,
+ TemplateArgument> {
+ friend class ASTStmtReader;
+ friend TrailingObjects;
+
+ // \brief The optional nested name specifier used when naming the concept.
+ NestedNameSpecifierLoc NestedNameSpec;
+
+ /// \brief The location of the template keyword, if specified when naming the
+ /// concept.
+ SourceLocation TemplateKWLoc;
+
+ /// \brief The location of the concept name in the expression.
+ SourceLocation ConceptNameLoc;
+
+ /// \brief The declaration found by name lookup when the expression was
+ /// created.
+ /// Can differ from NamedConcept when, for example, the concept was found
+ /// through a UsingShadowDecl.
+ NamedDecl *FoundDecl;
+
+ /// \brief The concept named, and whether or not the concept with the given
+ /// arguments was satisfied when the expression was created.
+ /// If any of the template arguments are dependent (this expr would then be
+ /// isValueDependent()), this bit is to be ignored.
+ llvm::PointerIntPair<ConceptDecl *, 1, bool> NamedConcept;
+
+ /// \brief The template argument list source info used to specialize the
+ /// concept.
+ const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
+
+ /// \brief The number of template arguments in the tail-allocated list of
+ /// converted template arguments.
+ unsigned NumTemplateArgs;
+
+ ConceptSpecializationExpr(ASTContext &C, NestedNameSpecifierLoc NNS,
+ SourceLocation TemplateKWLoc,
+ SourceLocation ConceptNameLoc, NamedDecl *FoundDecl,
+ ConceptDecl *NamedConcept,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ArrayRef<TemplateArgument> ConvertedArgs,
+ Optional<bool> IsSatisfied);
+
+ ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs);
+
+public:
+
+ static ConceptSpecializationExpr *
+ Create(ASTContext &C, NestedNameSpecifierLoc NNS,
+ SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc,
+ NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ArrayRef<TemplateArgument> ConvertedArgs, Optional<bool> IsSatisfied);
+
+ static ConceptSpecializationExpr *
+ Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs);
+
+ const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
+ return NestedNameSpec;
+ }
+
+ NamedDecl *getFoundDecl() const {
+ return FoundDecl;
+ }
+
+ ConceptDecl *getNamedConcept() const {
+ return NamedConcept.getPointer();
+ }
+
+ ArrayRef<TemplateArgument> getTemplateArguments() const {
+ return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(),
+ NumTemplateArgs);
+ }
+
+ const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
+ return ArgsAsWritten;
+ }
+
+ /// \brief Set new template arguments for this concept specialization.
+ void setTemplateArguments(const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ArrayRef<TemplateArgument> Converted);
+
+ /// \brief Whether or not the concept with the given arguments was satisfied
+ /// when the expression was created. This method assumes that the expression
+ /// is not dependent!
+ bool isSatisfied() const {
+ assert(!isValueDependent()
+ && "isSatisfied called on a dependent ConceptSpecializationExpr");
+ return NamedConcept.getInt();
+ }
+
+ SourceLocation getConceptNameLoc() const { return ConceptNameLoc; }
+
+ SourceLocation getTemplateKWLoc() const { return TemplateKWLoc; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ConceptSpecializationExprClass;
+ }
+
+ SourceLocation getBeginLoc() const LLVM_READONLY { return ConceptNameLoc; }
+ SourceLocation getEndLoc() const LLVM_READONLY {
+ return ArgsAsWritten->RAngleLoc;
+ }
+
+ // Iterators
+ child_range children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+};
+
} // namespace clang
#endif // LLVM_CLANG_AST_EXPRCXX_H
diff --git a/include/clang/AST/ExternalASTMerger.h b/include/clang/AST/ExternalASTMerger.h
index d89189da04f0..0230495a5ef3 100644
--- a/include/clang/AST/ExternalASTMerger.h
+++ b/include/clang/AST/ExternalASTMerger.h
@@ -14,6 +14,7 @@
#define LLVM_CLANG_AST_EXTERNALASTMERGER_H
#include "clang/AST/ASTImporter.h"
+#include "clang/AST/ASTImporterSharedState.h"
#include "clang/AST/ExternalASTSource.h"
#include "llvm/Support/raw_ostream.h"
@@ -22,7 +23,7 @@ namespace clang {
/// ExternalASTSource implementation that merges information from several
/// ASTContexts.
///
-/// ExtermalASTMerger maintains a vector of ASTImporters that it uses to import
+/// ExternalASTMerger maintains a vector of ASTImporters that it uses to import
/// (potentially incomplete) Decls and DeclContexts from the source ASTContexts
/// in response to ExternalASTSource API calls.
///
@@ -36,7 +37,7 @@ namespace clang {
/// lookup. In this case, Origins contains an entry overriding lookup and
/// specifying the correct pair of DeclContext/ASTContext.
///
-/// - The DeclContext of origin was determined by another ExterenalASTMerger.
+/// - The DeclContext of origin was determined by another ExternalASTMerger.
/// (This is possible when the source ASTContext for one of the Importers has
/// its own ExternalASTMerger). The origin must be properly forwarded in this
/// case.
@@ -79,20 +80,47 @@ public:
/// import SourceLocations properly. Additionally, when import occurs for
/// a DeclContext whose origin has been overridden, then this
/// ExternalASTMerger must be able to determine that.
- struct ImporterSource {
+ class ImporterSource {
ASTContext &AST;
FileManager &FM;
const OriginMap &OM;
+ /// True iff the source only exists temporary, i.e., it will be removed from
+ /// the ExternalASTMerger during the life time of the ExternalASTMerger.
+ bool Temporary;
+ /// If the ASTContext of this source has an ExternalASTMerger that imports
+ /// into this source, then this will point to that other ExternalASTMerger.
+ ExternalASTMerger *Merger;
+
+ public:
+ ImporterSource(ASTContext &AST, FileManager &FM, const OriginMap &OM,
+ bool Temporary = false, ExternalASTMerger *Merger = nullptr)
+ : AST(AST), FM(FM), OM(OM), Temporary(Temporary), Merger(Merger) {}
+ ASTContext &getASTContext() const { return AST; }
+ FileManager &getFileManager() const { return FM; }
+ const OriginMap &getOriginMap() const { return OM; }
+ bool isTemporary() const { return Temporary; }
+ ExternalASTMerger *getMerger() const { return Merger; }
};
private:
- /// The target for this ExtenralASTMerger.
+ /// The target for this ExternalASTMerger.
ImporterTarget Target;
+ /// ExternalASTMerger has multiple ASTImporters that import into the same
+ /// TU. This is the shared state for all ASTImporters of this
+ /// ExternalASTMerger.
+ /// See also the CrossTranslationUnitContext that has a similar setup.
+ std::shared_ptr<ASTImporterSharedState> SharedState;
public:
ExternalASTMerger(const ImporterTarget &Target,
llvm::ArrayRef<ImporterSource> Sources);
+ /// Asks all connected ASTImporters if any of them imported the given
+ /// declaration. If any ASTImporter did import the given declaration,
+ /// then this function returns the declaration that D was imported from.
+ /// Returns nullptr if no ASTImporter did import import D.
+ Decl *FindOriginalDecl(Decl *D);
+
/// Add a set of ASTContexts as possible origins.
///
/// Usually the set will be initialized in the constructor, but long-lived
@@ -145,7 +173,7 @@ public:
/// OriginContext.
bool HasImporterForOrigin(ASTContext &OriginContext);
- /// Returns a reference to the ASTRImporter from Importers whose origin
+ /// Returns a reference to the ASTImporter from Importers whose origin
/// is OriginContext. This allows manual import of ASTs while preserving the
/// OriginMap correctly.
ASTImporter &ImporterForOrigin(ASTContext &OriginContext);
diff --git a/include/clang/AST/FormatString.h b/include/clang/AST/FormatString.h
index 643fb822f7f4..8c944451f796 100644
--- a/include/clang/AST/FormatString.h
+++ b/include/clang/AST/FormatString.h
@@ -251,7 +251,21 @@ public:
enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,
AnyCharTy, CStrTy, WCStrTy, WIntTy };
- enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic };
+ /// How well a given conversion specifier matches its argument.
+ enum MatchKind {
+ /// The conversion specifier and the argument types are incompatible. For
+ /// instance, "%d" and float.
+ NoMatch = 0,
+ /// The conversion specifier and the argument type are compatible. For
+ /// instance, "%d" and _Bool.
+ Match = 1,
+ /// The conversion specifier and the argument type are disallowed by the C
+ /// standard, but are in practice harmless. For instance, "%p" and int*.
+ NoMatchPedantic,
+ /// The conversion specifier and the argument type are compatible, but still
+ /// seems likely to be an error. For instance, "%hd" and _Bool.
+ NoMatchTypeConfusion,
+ };
private:
const Kind K;
@@ -748,6 +762,12 @@ bool ParseScanfString(FormatStringHandler &H,
const char *beg, const char *end, const LangOptions &LO,
const TargetInfo &Target);
+/// Return true if the given string has at least one formatting specifier.
+bool parseFormatStringHasFormattingSpecifiers(const char *Begin,
+ const char *End,
+ const LangOptions &LO,
+ const TargetInfo &Target);
+
} // end analyze_format_string namespace
} // end clang namespace
#endif
diff --git a/include/clang/AST/GlobalDecl.h b/include/clang/AST/GlobalDecl.h
index 86fd0f6aa907..145e961a23a3 100644
--- a/include/clang/AST/GlobalDecl.h
+++ b/include/clang/AST/GlobalDecl.h
@@ -59,6 +59,7 @@ public:
GlobalDecl(const CapturedDecl *D) { Init(D); }
GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
GlobalDecl(const OMPDeclareReductionDecl *D) { Init(D); }
+ GlobalDecl(const OMPDeclareMapperDecl *D) { Init(D); }
GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type) : Value(D, Type) {}
GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type) : Value(D, Type) {}
GlobalDecl(const VarDecl *D, DynamicInitKind StubKind)
diff --git a/include/clang/AST/JSONNodeDumper.h b/include/clang/AST/JSONNodeDumper.h
index 238e43aad78b..5f34440b8b56 100644
--- a/include/clang/AST/JSONNodeDumper.h
+++ b/include/clang/AST/JSONNodeDumper.h
@@ -141,6 +141,8 @@ class JSONNodeDumper
JOS.attribute(Key, Value);
}
+ void writeIncludeStack(PresumedLoc Loc, bool JustFirst = false);
+
// Writes the attributes of a SourceLocation object without.
void writeBareSourceLocation(SourceLocation Loc, bool IsSpelling);
diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h
index b1fbe936136a..5db5c5b977da 100644
--- a/include/clang/AST/Mangle.h
+++ b/include/clang/AST/Mangle.h
@@ -56,7 +56,7 @@ private:
llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds;
llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds;
- llvm::DenseMap<const TagDecl*, uint64_t> AnonStructIds;
+ llvm::DenseMap<const NamedDecl*, uint64_t> AnonStructIds;
public:
ManglerKind getKind() const { return Kind; }
@@ -82,9 +82,9 @@ public:
return Result.first->second;
}
- uint64_t getAnonymousStructId(const TagDecl *TD) {
- std::pair<llvm::DenseMap<const TagDecl *, uint64_t>::iterator, bool>
- Result = AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size()));
+ uint64_t getAnonymousStructId(const NamedDecl *D) {
+ std::pair<llvm::DenseMap<const NamedDecl *, uint64_t>::iterator, bool>
+ Result = AnonStructIds.insert(std::make_pair(D, AnonStructIds.size()));
return Result.first->second;
}
@@ -170,6 +170,8 @@ public:
virtual void mangleCXXDtorComdat(const CXXDestructorDecl *D,
raw_ostream &) = 0;
+ virtual void mangleLambdaSig(const CXXRecordDecl *Lambda, raw_ostream &) = 0;
+
static bool classof(const MangleContext *C) {
return C->getKind() == MK_Itanium;
}
@@ -248,8 +250,16 @@ class ASTNameGenerator {
public:
explicit ASTNameGenerator(ASTContext &Ctx);
~ASTNameGenerator();
+
+ /// Writes name for \p D to \p OS.
+ /// \returns true on failure, false on success.
bool writeName(const Decl *D, raw_ostream &OS);
+
+ /// \returns name for \p D
std::string getName(const Decl *D);
+
+ /// \returns all applicable mangled names.
+ /// For example C++ constructors/destructors can have multiple.
std::vector<std::string> getAllManglings(const Decl *D);
private:
diff --git a/include/clang/AST/NSAPI.h b/include/clang/AST/NSAPI.h
index 21f0c5458d81..a8bd2d0f17e6 100644
--- a/include/clang/AST/NSAPI.h
+++ b/include/clang/AST/NSAPI.h
@@ -55,9 +55,6 @@ public:
/// The Objective-C NSString selectors.
Selector getNSStringSelector(NSStringMethodKind MK) const;
- /// Return NSStringMethodKind if \param Sel is such a selector.
- Optional<NSStringMethodKind> getNSStringMethodKind(Selector Sel) const;
-
/// Returns true if the expression \param E is a reference of
/// "NSUTF8StringEncoding" enum constant.
bool isNSUTF8StringEncodingConstant(const Expr *E) const {
diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h
index eadcc62a3457..b2a2035dcb3c 100644
--- a/include/clang/AST/OpenMPClause.h
+++ b/include/clang/AST/OpenMPClause.h
@@ -519,7 +519,7 @@ public:
/// \endcode
/// In this example directive '#pragma omp task' has simple 'final'
/// clause with condition 'a > 5'.
-class OMPFinalClause : public OMPClause {
+class OMPFinalClause : public OMPClause, public OMPClauseWithPreInit {
friend class OMPClauseReader;
/// Location of '('.
@@ -534,18 +534,25 @@ class OMPFinalClause : public OMPClause {
public:
/// Build 'final' clause with condition \a Cond.
///
+ /// \param Cond Condition of the clause.
+ /// \param HelperCond Helper condition for the construct.
+ /// \param CaptureRegion Innermost OpenMP region where expressions in this
+ /// clause must be captured.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
- /// \param Cond Condition of the clause.
/// \param EndLoc Ending location of the clause.
- OMPFinalClause(Expr *Cond, SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation EndLoc)
- : OMPClause(OMPC_final, StartLoc, EndLoc), LParenLoc(LParenLoc),
- Condition(Cond) {}
+ OMPFinalClause(Expr *Cond, Stmt *HelperCond,
+ OpenMPDirectiveKind CaptureRegion, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_final, StartLoc, EndLoc), OMPClauseWithPreInit(this),
+ LParenLoc(LParenLoc), Condition(Cond) {
+ setPreInitStmt(HelperCond, CaptureRegion);
+ }
/// Build an empty clause.
OMPFinalClause()
- : OMPClause(OMPC_final, SourceLocation(), SourceLocation()) {}
+ : OMPClause(OMPC_final, SourceLocation(), SourceLocation()),
+ OMPClauseWithPreInit(this) {}
/// Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
@@ -562,11 +569,10 @@ public:
return const_child_range(&Condition, &Condition + 1);
}
- child_range used_children() {
- return child_range(child_iterator(), child_iterator());
- }
+ child_range used_children();
const_child_range used_children() const {
- return const_child_range(const_child_iterator(), const_child_iterator());
+ auto Children = const_cast<OMPFinalClause *>(this)->used_children();
+ return const_child_range(Children.begin(), Children.end());
}
static bool classof(const OMPClause *T) {
@@ -2099,10 +2105,12 @@ public:
}
child_range used_children() {
- return child_range(child_iterator(), child_iterator());
+ return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(varlist_end()));
}
const_child_range used_children() const {
- return const_child_range(const_child_iterator(), const_child_iterator());
+ auto Children = const_cast<OMPFirstprivateClause *>(this)->used_children();
+ return const_child_range(Children.begin(), Children.end());
}
static bool classof(const OMPClause *T) {
@@ -2616,10 +2624,12 @@ public:
}
child_range used_children() {
- return child_range(child_iterator(), child_iterator());
+ return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(varlist_end()));
}
const_child_range used_children() const {
- return const_child_range(const_child_iterator(), const_child_iterator());
+ auto Children = const_cast<OMPReductionClause *>(this)->used_children();
+ return const_child_range(Children.begin(), Children.end());
}
static bool classof(const OMPClause *T) {
@@ -3212,6 +3222,14 @@ class OMPLinearClause final
return llvm::makeArrayRef(getUpdates().end(), varlist_size());
}
+ /// Gets the list of used expressions for linear variables.
+ MutableArrayRef<Expr *> getUsedExprs() {
+ return MutableArrayRef<Expr *>(getFinals().end() + 2, varlist_size() + 1);
+ }
+ ArrayRef<const Expr *> getUsedExprs() const {
+ return llvm::makeArrayRef(getFinals().end() + 2, varlist_size() + 1);
+ }
+
/// Sets the list of the copies of original linear variables.
/// \param PL List of expressions.
void setPrivates(ArrayRef<Expr *> PL);
@@ -3291,6 +3309,9 @@ public:
/// \param FL List of expressions.
void setFinals(ArrayRef<Expr *> FL);
+ /// Sets the list of used expressions for the linear clause.
+ void setUsedExprs(ArrayRef<Expr *> UE);
+
using privates_iterator = MutableArrayRef<Expr *>::iterator;
using privates_const_iterator = ArrayRef<const Expr *>::iterator;
using privates_range = llvm::iterator_range<privates_iterator>;
@@ -3343,6 +3364,21 @@ public:
return finals_const_range(getFinals().begin(), getFinals().end());
}
+ using used_expressions_iterator = MutableArrayRef<Expr *>::iterator;
+ using used_expressions_const_iterator = ArrayRef<const Expr *>::iterator;
+ using used_expressions_range =
+ llvm::iterator_range<used_expressions_iterator>;
+ using used_expressions_const_range =
+ llvm::iterator_range<used_expressions_const_iterator>;
+
+ used_expressions_range used_expressions() {
+ return finals_range(getUsedExprs().begin(), getUsedExprs().end());
+ }
+
+ used_expressions_const_range used_expressions() const {
+ return finals_const_range(getUsedExprs().begin(), getUsedExprs().end());
+ }
+
child_range children() {
return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
reinterpret_cast<Stmt **>(varlist_end()));
@@ -3353,11 +3389,11 @@ public:
return const_child_range(Children.begin(), Children.end());
}
- child_range used_children() {
- return child_range(child_iterator(), child_iterator());
- }
+ child_range used_children();
+
const_child_range used_children() const {
- return const_child_range(const_child_iterator(), const_child_iterator());
+ auto Children = const_cast<OMPLinearClause *>(this)->used_children();
+ return const_child_range(Children.begin(), Children.end());
}
static bool classof(const OMPClause *T) {
@@ -4995,12 +5031,17 @@ public:
}
child_range used_children() {
+ if (MapType == OMPC_MAP_to || MapType == OMPC_MAP_tofrom)
+ return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(varlist_end()));
return child_range(child_iterator(), child_iterator());
}
const_child_range used_children() const {
- return const_child_range(const_child_iterator(), const_child_iterator());
+ auto Children = const_cast<OMPMapClause *>(this)->used_children();
+ return const_child_range(Children.begin(), Children.end());
}
+
static bool classof(const OMPClause *T) {
return T->getClauseKind() == OMPC_map;
}
@@ -5165,7 +5206,7 @@ public:
/// \endcode
/// In this example directive '#pragma omp teams' has clause 'priority' with
/// single expression 'n'.
-class OMPPriorityClause : public OMPClause {
+class OMPPriorityClause : public OMPClause, public OMPClauseWithPreInit {
friend class OMPClauseReader;
/// Location of '('.
@@ -5182,18 +5223,25 @@ class OMPPriorityClause : public OMPClause {
public:
/// Build 'priority' clause.
///
- /// \param E Expression associated with this clause.
+ /// \param Priority Expression associated with this clause.
+ /// \param HelperPriority Helper priority for the construct.
+ /// \param CaptureRegion Innermost OpenMP region where expressions in this
+ /// clause must be captured.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
- OMPPriorityClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation EndLoc)
- : OMPClause(OMPC_priority, StartLoc, EndLoc), LParenLoc(LParenLoc),
- Priority(E) {}
+ OMPPriorityClause(Expr *Priority, Stmt *HelperPriority,
+ OpenMPDirectiveKind CaptureRegion, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc)
+ : OMPClause(OMPC_priority, StartLoc, EndLoc), OMPClauseWithPreInit(this),
+ LParenLoc(LParenLoc), Priority(Priority) {
+ setPreInitStmt(HelperPriority, CaptureRegion);
+ }
/// Build an empty clause.
OMPPriorityClause()
- : OMPClause(OMPC_priority, SourceLocation(), SourceLocation()) {}
+ : OMPClause(OMPC_priority, SourceLocation(), SourceLocation()),
+ OMPClauseWithPreInit(this) {}
/// Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
@@ -5213,11 +5261,10 @@ public:
return const_child_range(&Priority, &Priority + 1);
}
- child_range used_children() {
- return child_range(child_iterator(), child_iterator());
- }
+ child_range used_children();
const_child_range used_children() const {
- return const_child_range(const_child_iterator(), const_child_iterator());
+ auto Children = const_cast<OMPPriorityClause *>(this)->used_children();
+ return const_child_range(Children.begin(), Children.end());
}
static bool classof(const OMPClause *T) {
@@ -5233,7 +5280,7 @@ public:
/// \endcode
/// In this example directive '#pragma omp taskloop' has clause 'grainsize'
/// with single expression '4'.
-class OMPGrainsizeClause : public OMPClause {
+class OMPGrainsizeClause : public OMPClause, public OMPClauseWithPreInit {
friend class OMPClauseReader;
/// Location of '('.
@@ -5249,16 +5296,23 @@ public:
/// Build 'grainsize' clause.
///
/// \param Size Expression associated with this clause.
+ /// \param HelperSize Helper grainsize for the construct.
+ /// \param CaptureRegion Innermost OpenMP region where expressions in this
+ /// clause must be captured.
/// \param StartLoc Starting location of the clause.
/// \param EndLoc Ending location of the clause.
- OMPGrainsizeClause(Expr *Size, SourceLocation StartLoc,
+ OMPGrainsizeClause(Expr *Size, Stmt *HelperSize,
+ OpenMPDirectiveKind CaptureRegion, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc)
- : OMPClause(OMPC_grainsize, StartLoc, EndLoc), LParenLoc(LParenLoc),
- Grainsize(Size) {}
+ : OMPClause(OMPC_grainsize, StartLoc, EndLoc), OMPClauseWithPreInit(this),
+ LParenLoc(LParenLoc), Grainsize(Size) {
+ setPreInitStmt(HelperSize, CaptureRegion);
+ }
/// Build an empty clause.
explicit OMPGrainsizeClause()
- : OMPClause(OMPC_grainsize, SourceLocation(), SourceLocation()) {}
+ : OMPClause(OMPC_grainsize, SourceLocation(), SourceLocation()),
+ OMPClauseWithPreInit(this) {}
/// Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
@@ -5275,11 +5329,10 @@ public:
return const_child_range(&Grainsize, &Grainsize + 1);
}
- child_range used_children() {
- return child_range(child_iterator(), child_iterator());
- }
+ child_range used_children();
const_child_range used_children() const {
- return const_child_range(const_child_iterator(), const_child_iterator());
+ auto Children = const_cast<OMPGrainsizeClause *>(this)->used_children();
+ return const_child_range(Children.begin(), Children.end());
}
static bool classof(const OMPClause *T) {
@@ -5334,7 +5387,7 @@ public:
/// \endcode
/// In this example directive '#pragma omp taskloop' has clause 'num_tasks'
/// with single expression '4'.
-class OMPNumTasksClause : public OMPClause {
+class OMPNumTasksClause : public OMPClause, public OMPClauseWithPreInit {
friend class OMPClauseReader;
/// Location of '('.
@@ -5350,16 +5403,23 @@ public:
/// Build 'num_tasks' clause.
///
/// \param Size Expression associated with this clause.
+ /// \param HelperSize Helper grainsize for the construct.
+ /// \param CaptureRegion Innermost OpenMP region where expressions in this
+ /// clause must be captured.
/// \param StartLoc Starting location of the clause.
/// \param EndLoc Ending location of the clause.
- OMPNumTasksClause(Expr *Size, SourceLocation StartLoc,
+ OMPNumTasksClause(Expr *Size, Stmt *HelperSize,
+ OpenMPDirectiveKind CaptureRegion, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc)
- : OMPClause(OMPC_num_tasks, StartLoc, EndLoc), LParenLoc(LParenLoc),
- NumTasks(Size) {}
+ : OMPClause(OMPC_num_tasks, StartLoc, EndLoc), OMPClauseWithPreInit(this),
+ LParenLoc(LParenLoc), NumTasks(Size) {
+ setPreInitStmt(HelperSize, CaptureRegion);
+ }
/// Build an empty clause.
explicit OMPNumTasksClause()
- : OMPClause(OMPC_num_tasks, SourceLocation(), SourceLocation()) {}
+ : OMPClause(OMPC_num_tasks, SourceLocation(), SourceLocation()),
+ OMPClauseWithPreInit(this) {}
/// Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
@@ -5376,11 +5436,10 @@ public:
return const_child_range(&NumTasks, &NumTasks + 1);
}
- child_range used_children() {
- return child_range(child_iterator(), child_iterator());
- }
+ child_range used_children();
const_child_range used_children() const {
- return const_child_range(const_child_iterator(), const_child_iterator());
+ auto Children = const_cast<OMPNumTasksClause *>(this)->used_children();
+ return const_child_range(Children.begin(), Children.end());
}
static bool classof(const OMPClause *T) {
diff --git a/include/clang/AST/OperationKinds.def b/include/clang/AST/OperationKinds.def
index 9af92c1ae7ff..f29664e8eb33 100644
--- a/include/clang/AST/OperationKinds.def
+++ b/include/clang/AST/OperationKinds.def
@@ -66,8 +66,9 @@ CAST_OPERATION(BitCast)
/// bool b; reinterpret_cast<char&>(b) = 'a';
CAST_OPERATION(LValueBitCast)
-/// CK_LValueToRValueBitCast - A conversion that causes us to reinterpret an
-/// lvalue as an rvalue of a different type. Created by __builtin_bit_cast.
+/// CK_LValueToRValueBitCast - A conversion that causes us to reinterpret the
+/// object representation of an lvalue as an rvalue. Created by
+/// __builtin_bit_cast.
CAST_OPERATION(LValueToRValueBitCast)
/// CK_LValueToRValue - A conversion which causes the extraction of
diff --git a/include/clang/AST/OptionalDiagnostic.h b/include/clang/AST/OptionalDiagnostic.h
new file mode 100644
index 000000000000..c57199f0fdf1
--- /dev/null
+++ b/include/clang/AST/OptionalDiagnostic.h
@@ -0,0 +1,78 @@
+//===- OptionalDiagnostic.h - An optional diagnostic ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Implements a partial diagnostic which may not be emitted.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_OPTIONALDIAGNOSTIC_H
+#define LLVM_CLANG_AST_OPTIONALDIAGNOSTIC_H
+
+#include "clang/AST/APValue.h"
+#include "clang/Basic/PartialDiagnostic.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+
+/// 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 = nullptr) : Diag(Diag) {}
+
+ template <typename T> OptionalDiagnostic &operator<<(const T &v) {
+ if (Diag)
+ *Diag << v;
+ return *this;
+ }
+
+ OptionalDiagnostic &operator<<(const llvm::APSInt &I) {
+ if (Diag) {
+ SmallVector<char, 32> Buffer;
+ I.toString(Buffer);
+ *Diag << StringRef(Buffer.data(), Buffer.size());
+ }
+ return *this;
+ }
+
+ OptionalDiagnostic &operator<<(const llvm::APFloat &F) {
+ if (Diag) {
+ // FIXME: Force the precision of the source value down so we don't
+ // print digits which are usually useless (we don't really care here if
+ // we truncate a digit by accident in edge cases). Ideally,
+ // APFloat::toString would automatically print the shortest
+ // representation which rounds to the correct value, but it's a bit
+ // tricky to implement. Could use std::to_chars.
+ unsigned precision = llvm::APFloat::semanticsPrecision(F.getSemantics());
+ precision = (precision * 59 + 195) / 196;
+ SmallVector<char, 32> Buffer;
+ F.toString(Buffer, precision);
+ *Diag << StringRef(Buffer.data(), Buffer.size());
+ }
+ return *this;
+ }
+
+ OptionalDiagnostic &operator<<(const APFixedPoint &FX) {
+ if (Diag) {
+ SmallVector<char, 32> Buffer;
+ FX.toString(Buffer);
+ *Diag << StringRef(Buffer.data(), Buffer.size());
+ }
+ return *this;
+ }
+};
+
+} // namespace clang
+
+#endif
diff --git a/include/clang/AST/RawCommentList.h b/include/clang/AST/RawCommentList.h
index 5dc8694e77e9..1eea56dee622 100644
--- a/include/clang/AST/RawCommentList.h
+++ b/include/clang/AST/RawCommentList.h
@@ -10,8 +10,11 @@
#define LLVM_CLANG_AST_RAWCOMMENTLIST_H
#include "clang/Basic/CommentOptions.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include <map>
namespace clang {
@@ -196,17 +199,25 @@ public:
void addComment(const RawComment &RC, const CommentOptions &CommentOpts,
llvm::BumpPtrAllocator &Allocator);
- ArrayRef<RawComment *> getComments() const {
- return Comments;
- }
+ /// \returns A mapping from an offset of the start of the comment to the
+ /// comment itself, or nullptr in case there are no comments in \p File.
+ const std::map<unsigned, RawComment *> *getCommentsInFile(FileID File) const;
+
+ bool empty() const;
+
+ unsigned getCommentBeginLine(RawComment *C, FileID File,
+ unsigned Offset) const;
+ unsigned getCommentEndOffset(RawComment *C) const;
private:
SourceManager &SourceMgr;
- std::vector<RawComment *> Comments;
-
- void addDeserializedComments(ArrayRef<RawComment *> DeserializedComments);
+ // mapping: FileId -> comment begin offset -> comment
+ llvm::DenseMap<FileID, std::map<unsigned, RawComment *>> OrderedComments;
+ mutable llvm::DenseMap<RawComment *, unsigned> CommentBeginLine;
+ mutable llvm::DenseMap<RawComment *, unsigned> CommentEndOffset;
friend class ASTReader;
+ friend class ASTWriter;
};
} // end namespace clang
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 698fba2f4ed1..5b58eab95d60 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -431,7 +431,7 @@ public:
// Declare Traverse*() for all concrete Type classes.
#define ABSTRACT_TYPE(CLASS, BASE)
#define TYPE(CLASS, BASE) bool Traverse##CLASS##Type(CLASS##Type *T);
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
// The above header #undefs ABSTRACT_TYPE and TYPE upon exit.
// Define WalkUpFrom*() and empty Visit*() for all Type classes.
@@ -444,7 +444,7 @@ public:
return true; \
} \
bool Visit##CLASS##Type(CLASS##Type *T) { return true; }
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
// ---- Methods on TypeLocs ----
// FIXME: this currently just calls the matching Type methods
@@ -460,7 +460,7 @@ public:
bool VisitTypeLoc(TypeLoc TL) { return true; }
// QualifiedTypeLoc and UnqualTypeLoc are not declared in
- // TypeNodes.def and thus need to be handled specially.
+ // TypeNodes.inc and thus need to be handled specially.
bool WalkUpFromQualifiedTypeLoc(QualifiedTypeLoc TL) {
return getDerived().VisitUnqualTypeLoc(TL.getUnqualifiedLoc());
}
@@ -478,7 +478,7 @@ public:
return true; \
} \
bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { return true; }
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
// ---- Methods on Decls ----
@@ -676,7 +676,7 @@ bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) {
#define TYPE(CLASS, BASE) \
case Type::CLASS: \
DISPATCH(CLASS##Type, CLASS##Type, const_cast<Type *>(T.getTypePtr()));
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
return true;
@@ -722,12 +722,6 @@ bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) {
break;
#include "clang/AST/DeclNodes.inc"
}
-
- // Visit any attributes attached to this declaration.
- for (auto *I : D->attrs()) {
- if (!getDerived().TraverseAttr(I))
- return false;
- }
return true;
}
@@ -965,8 +959,11 @@ DEF_TRAVERSE_TYPE(AdjustedType, { TRY_TO(TraverseType(T->getOriginalType())); })
DEF_TRAVERSE_TYPE(DecayedType, { TRY_TO(TraverseType(T->getOriginalType())); })
-DEF_TRAVERSE_TYPE(ConstantArrayType,
- { TRY_TO(TraverseType(T->getElementType())); })
+DEF_TRAVERSE_TYPE(ConstantArrayType, {
+ TRY_TO(TraverseType(T->getElementType()));
+ if (T->getSizeExpr())
+ TRY_TO(TraverseStmt(const_cast<Expr*>(T->getSizeExpr())));
+})
DEF_TRAVERSE_TYPE(IncompleteArrayType,
{ TRY_TO(TraverseType(T->getElementType())); })
@@ -1407,6 +1404,11 @@ bool RecursiveASTVisitor<Derived>::TraverseDeclContextHelper(DeclContext *DC) {
{ CODE; } \
if (ReturnValue && ShouldVisitChildren) \
TRY_TO(TraverseDeclContextHelper(dyn_cast<DeclContext>(D))); \
+ if (ReturnValue) { \
+ /* Visit any attributes attached to this declaration. */ \
+ for (auto *I : D->attrs()) \
+ TRY_TO(getDerived().TraverseAttr(I)); \
+ } \
if (ReturnValue && getDerived().shouldTraversePostOrder()) \
TRY_TO(WalkUpFrom##DECL(D)); \
return ReturnValue; \
@@ -1631,9 +1633,11 @@ template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
TemplateParameterList *TPL) {
if (TPL) {
- for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end();
- I != E; ++I) {
- TRY_TO(TraverseDecl(*I));
+ for (NamedDecl *D : *TPL) {
+ TRY_TO(TraverseDecl(D));
+ }
+ if (Expr *RequiresClause = TPL->getRequiresClause()) {
+ TRY_TO(TraverseStmt(RequiresClause));
}
}
return true;
@@ -2023,11 +2027,18 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
// Constructor initializers.
for (auto *I : Ctor->inits()) {
- TRY_TO(TraverseConstructorInitializer(I));
+ if (I->isWritten() || getDerived().shouldVisitImplicitCode())
+ TRY_TO(TraverseConstructorInitializer(I));
}
}
- if (D->isThisDeclarationADefinition()) {
+ bool VisitBody = D->isThisDeclarationADefinition();
+ // If a method is set to default outside the class definition the compiler
+ // generates the method body and adds it to the AST.
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(D))
+ VisitBody &= !MD->isDefaulted() || getDerived().shouldVisitImplicitCode();
+
+ if (VisitBody) {
TRY_TO(TraverseStmt(D->getBody())); // Function body.
}
return true;
@@ -2308,19 +2319,30 @@ bool RecursiveASTVisitor<Derived>::TraverseSynOrSemInitListExpr(
return true;
}
-// This method is called once for each pair of syntactic and semantic
-// InitListExpr, and it traverses the subtrees defined by the two forms. This
-// may cause some of the children to be visited twice, if they appear both in
-// the syntactic and the semantic form.
+// If shouldVisitImplicitCode() returns false, this method traverses only the
+// syntactic form of InitListExpr.
+// If shouldVisitImplicitCode() return true, this method is called once for
+// each pair of syntactic and semantic InitListExpr, and it traverses the
+// subtrees defined by the two forms. This may cause some of the children to be
+// visited twice, if they appear both in the syntactic and the semantic form.
//
// There is no guarantee about which form \p S takes when this method is called.
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(
InitListExpr *S, DataRecursionQueue *Queue) {
+ if (S->isSemanticForm() && S->isSyntacticForm()) {
+ // `S` does not have alternative forms, traverse only once.
+ TRY_TO(TraverseSynOrSemInitListExpr(S, Queue));
+ return true;
+ }
TRY_TO(TraverseSynOrSemInitListExpr(
S->isSemanticForm() ? S->getSyntacticForm() : S, Queue));
- TRY_TO(TraverseSynOrSemInitListExpr(
- S->isSemanticForm() ? S : S->getSemanticForm(), Queue));
+ if (getDerived().shouldVisitImplicitCode()) {
+ // Only visit the semantic form if the clients are interested in implicit
+ // compiler-generated.
+ TRY_TO(TraverseSynOrSemInitListExpr(
+ S->isSemanticForm() ? S : S->getSemanticForm(), Queue));
+ }
return true;
}
@@ -2584,6 +2606,15 @@ DEF_TRAVERSE_STMT(SEHLeaveStmt, {})
DEF_TRAVERSE_STMT(CapturedStmt, { TRY_TO(TraverseDecl(S->getCapturedDecl())); })
DEF_TRAVERSE_STMT(CXXOperatorCallExpr, {})
+DEF_TRAVERSE_STMT(CXXRewrittenBinaryOperator, {
+ if (!getDerived().shouldVisitImplicitCode()) {
+ CXXRewrittenBinaryOperator::DecomposedForm Decomposed =
+ S->getDecomposedForm();
+ TRY_TO(TraverseStmt(const_cast<Expr*>(Decomposed.LHS)));
+ TRY_TO(TraverseStmt(const_cast<Expr*>(Decomposed.RHS)));
+ ShouldVisitChildren = false;
+ }
+})
DEF_TRAVERSE_STMT(OpaqueValueExpr, {})
DEF_TRAVERSE_STMT(TypoExpr, {})
DEF_TRAVERSE_STMT(CUDAKernelCallExpr, {})
@@ -2639,6 +2670,12 @@ DEF_TRAVERSE_STMT(CoyieldExpr, {
}
})
+DEF_TRAVERSE_STMT(ConceptSpecializationExpr, {
+ TRY_TO(TraverseTemplateArgumentLocsHelper(
+ S->getTemplateArgsAsWritten()->getTemplateArgs(),
+ S->getTemplateArgsAsWritten()->NumTemplateArgs));
+})
+
// These literals (all of them) do not need any action.
DEF_TRAVERSE_STMT(IntegerLiteral, {})
DEF_TRAVERSE_STMT(FixedPointLiteral, {})
@@ -2768,6 +2805,15 @@ DEF_TRAVERSE_STMT(OMPTaskLoopDirective,
DEF_TRAVERSE_STMT(OMPTaskLoopSimdDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPMasterTaskLoopDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
+DEF_TRAVERSE_STMT(OMPMasterTaskLoopSimdDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
+DEF_TRAVERSE_STMT(OMPParallelMasterTaskLoopDirective,
+ { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
DEF_TRAVERSE_STMT(OMPDistributeDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
@@ -2826,6 +2872,8 @@ bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) {
#include "clang/Basic/OpenMPKinds.def"
case OMPC_threadprivate:
case OMPC_uniform:
+ case OMPC_device_type:
+ case OMPC_match:
case OMPC_unknown:
break;
}
@@ -2870,6 +2918,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPIfClause(OMPIfClause *C) {
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPFinalClause(OMPFinalClause *C) {
+ TRY_TO(VisitOMPClauseWithPreInit(C));
TRY_TO(TraverseStmt(C->getCondition()));
return true;
}
@@ -3240,6 +3289,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPThreadLimitClause(
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPPriorityClause(
OMPPriorityClause *C) {
+ TRY_TO(VisitOMPClauseWithPreInit(C));
TRY_TO(TraverseStmt(C->getPriority()));
return true;
}
@@ -3247,6 +3297,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPPriorityClause(
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPGrainsizeClause(
OMPGrainsizeClause *C) {
+ TRY_TO(VisitOMPClauseWithPreInit(C));
TRY_TO(TraverseStmt(C->getGrainsize()));
return true;
}
@@ -3254,6 +3305,7 @@ bool RecursiveASTVisitor<Derived>::VisitOMPGrainsizeClause(
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPNumTasksClause(
OMPNumTasksClause *C) {
+ TRY_TO(VisitOMPClauseWithPreInit(C));
TRY_TO(TraverseStmt(C->getNumTasks()));
return true;
}
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 403b88ac3a3c..7aebbf2cb6a3 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -604,6 +604,15 @@ protected:
unsigned FPFeatures : 3;
};
+ class CXXRewrittenBinaryOperatorBitfields {
+ friend class ASTStmtReader;
+ friend class CXXRewrittenBinaryOperator;
+
+ unsigned : NumCallExprBits;
+
+ unsigned IsReversed : 1;
+ };
+
class CXXBoolLiteralExprBitfields {
friend class CXXBoolLiteralExpr;
@@ -978,6 +987,7 @@ protected:
// C++ Expressions
CXXOperatorCallExprBitfields CXXOperatorCallExprBits;
+ CXXRewrittenBinaryOperatorBitfields CXXRewrittenBinaryOperatorBits;
CXXBoolLiteralExprBitfields CXXBoolLiteralExprBits;
CXXNullPtrLiteralExprBitfields CXXNullPtrLiteralExprBits;
CXXThisExprBitfields CXXThisExprBits;
diff --git a/include/clang/AST/StmtOpenMP.h b/include/clang/AST/StmtOpenMP.h
index e37f5b1e0004..ddfb3060b158 100644
--- a/include/clang/AST/StmtOpenMP.h
+++ b/include/clang/AST/StmtOpenMP.h
@@ -17,6 +17,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/OpenMPClause.h"
#include "clang/AST/Stmt.h"
+#include "clang/AST/StmtCXX.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/SourceLocation.h"
@@ -448,7 +449,8 @@ class OMPLoopDirective : public OMPExecutableDirective {
PreInitsOffset = 8,
// The '...End' enumerators do not correspond to child expressions - they
// specify the offset to the end (and start of the following counters/
- // updates/finals arrays).
+ // updates/finals/dependent_counters/dependent_inits/finals_conditions
+ // arrays).
DefaultEnd = 9,
// The following 8 exprs are used by worksharing and distribute loops only.
IsLastIterVariableOffset = 9,
@@ -474,7 +476,8 @@ class OMPLoopDirective : public OMPExecutableDirective {
CombinedNextUpperBoundOffset = 27,
CombinedDistConditionOffset = 28,
CombinedParForInDistConditionOffset = 29,
- // Offset to the end (and start of the following counters/updates/finals
+ // Offset to the end (and start of the following
+ // counters/updates/finals/dependent_counters/dependent_inits/finals_conditions
// arrays) for combined distribute loop directives.
CombinedDistributeEnd = 30,
};
@@ -517,6 +520,30 @@ class OMPLoopDirective : public OMPExecutableDirective {
return MutableArrayRef<Expr *>(Storage, CollapsedNum);
}
+ /// Get the dependent counters storage.
+ MutableArrayRef<Expr *> getDependentCounters() {
+ Expr **Storage = reinterpret_cast<Expr **>(
+ &*std::next(child_begin(),
+ getArraysOffset(getDirectiveKind()) + 5 * CollapsedNum));
+ return MutableArrayRef<Expr *>(Storage, CollapsedNum);
+ }
+
+ /// Get the dependent inits storage.
+ MutableArrayRef<Expr *> getDependentInits() {
+ Expr **Storage = reinterpret_cast<Expr **>(
+ &*std::next(child_begin(),
+ getArraysOffset(getDirectiveKind()) + 6 * CollapsedNum));
+ return MutableArrayRef<Expr *>(Storage, CollapsedNum);
+ }
+
+ /// Get the finals conditions storage.
+ MutableArrayRef<Expr *> getFinalsConditions() {
+ Expr **Storage = reinterpret_cast<Expr **>(
+ &*std::next(child_begin(),
+ getArraysOffset(getDirectiveKind()) + 7 * CollapsedNum));
+ return MutableArrayRef<Expr *>(Storage, CollapsedNum);
+ }
+
protected:
/// Build instance of loop directive of class \a Kind.
///
@@ -551,9 +578,10 @@ protected:
/// Children number.
static unsigned numLoopChildren(unsigned CollapsedNum,
OpenMPDirectiveKind Kind) {
- return getArraysOffset(Kind) + 5 * CollapsedNum; // Counters,
- // PrivateCounters, Inits,
- // Updates and Finals
+ return getArraysOffset(Kind) +
+ 8 * CollapsedNum; // Counters, PrivateCounters, Inits,
+ // Updates, Finals, DependentCounters,
+ // DependentInits, FinalsConditions.
}
void setIterationVariable(Expr *IV) {
@@ -703,6 +731,9 @@ protected:
void setInits(ArrayRef<Expr *> A);
void setUpdates(ArrayRef<Expr *> A);
void setFinals(ArrayRef<Expr *> A);
+ void setDependentCounters(ArrayRef<Expr *> A);
+ void setDependentInits(ArrayRef<Expr *> A);
+ void setFinalsConditions(ArrayRef<Expr *> A);
public:
/// The expressions built to support OpenMP loops in combined/composite
@@ -798,6 +829,15 @@ public:
SmallVector<Expr *, 4> Updates;
/// Final loop counter values for GodeGen.
SmallVector<Expr *, 4> Finals;
+ /// List of counters required for the generation of the non-rectangular
+ /// loops.
+ SmallVector<Expr *, 4> DependentCounters;
+ /// List of initializers required for the generation of the non-rectangular
+ /// loops.
+ SmallVector<Expr *, 4> DependentInits;
+ /// List of final conditions required for the generation of the
+ /// non-rectangular loops.
+ SmallVector<Expr *, 4> FinalsConditions;
/// Init statement for all captured expressions.
Stmt *PreInits;
@@ -813,7 +853,9 @@ public:
}
/// Initialize all the fields to null.
- /// \param Size Number of elements in the counters/finals/updates arrays.
+ /// \param Size Number of elements in the
+ /// counters/finals/updates/dependent_counters/dependent_inits/finals_conditions
+ /// arrays.
void clear(unsigned Size) {
IterationVarRef = nullptr;
LastIteration = nullptr;
@@ -839,12 +881,18 @@ public:
Inits.resize(Size);
Updates.resize(Size);
Finals.resize(Size);
+ DependentCounters.resize(Size);
+ DependentInits.resize(Size);
+ FinalsConditions.resize(Size);
for (unsigned i = 0; i < Size; ++i) {
Counters[i] = nullptr;
PrivateCounters[i] = nullptr;
Inits[i] = nullptr;
Updates[i] = nullptr;
Finals[i] = nullptr;
+ DependentCounters[i] = nullptr;
+ DependentInits[i] = nullptr;
+ FinalsConditions[i] = nullptr;
}
PreInits = nullptr;
DistCombinedFields.LB = nullptr;
@@ -1040,10 +1088,22 @@ public:
// This relies on the loop form is already checked by Sema.
const Stmt *Body =
getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
- Body = cast<ForStmt>(Body)->getBody();
+ if (auto *For = dyn_cast<ForStmt>(Body)) {
+ Body = For->getBody();
+ } else {
+ assert(isa<CXXForRangeStmt>(Body) &&
+ "Expected canonical for loop or range-based for loop.");
+ Body = cast<CXXForRangeStmt>(Body)->getBody();
+ }
for (unsigned Cnt = 1; Cnt < CollapsedNum; ++Cnt) {
Body = Body->IgnoreContainers();
- Body = cast<ForStmt>(Body)->getBody();
+ if (auto *For = dyn_cast<ForStmt>(Body)) {
+ Body = For->getBody();
+ } else {
+ assert(isa<CXXForRangeStmt>(Body) &&
+ "Expected canonical for loop or range-based for loop.");
+ Body = cast<CXXForRangeStmt>(Body)->getBody();
+ }
}
return Body;
}
@@ -1078,6 +1138,24 @@ public:
return const_cast<OMPLoopDirective *>(this)->getFinals();
}
+ ArrayRef<Expr *> dependent_counters() { return getDependentCounters(); }
+
+ ArrayRef<Expr *> dependent_counters() const {
+ return const_cast<OMPLoopDirective *>(this)->getDependentCounters();
+ }
+
+ ArrayRef<Expr *> dependent_inits() { return getDependentInits(); }
+
+ ArrayRef<Expr *> dependent_inits() const {
+ return const_cast<OMPLoopDirective *>(this)->getDependentInits();
+ }
+
+ ArrayRef<Expr *> finals_conditions() { return getFinalsConditions(); }
+
+ ArrayRef<Expr *> finals_conditions() const {
+ return const_cast<OMPLoopDirective *>(this)->getFinalsConditions();
+ }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPSimdDirectiveClass ||
T->getStmtClass() == OMPForDirectiveClass ||
@@ -1086,6 +1164,9 @@ public:
T->getStmtClass() == OMPParallelForSimdDirectiveClass ||
T->getStmtClass() == OMPTaskLoopDirectiveClass ||
T->getStmtClass() == OMPTaskLoopSimdDirectiveClass ||
+ T->getStmtClass() == OMPMasterTaskLoopDirectiveClass ||
+ T->getStmtClass() == OMPMasterTaskLoopSimdDirectiveClass ||
+ T->getStmtClass() == OMPParallelMasterTaskLoopDirectiveClass ||
T->getStmtClass() == OMPDistributeDirectiveClass ||
T->getStmtClass() == OMPTargetParallelForDirectiveClass ||
T->getStmtClass() == OMPDistributeParallelForDirectiveClass ||
@@ -3041,6 +3122,211 @@ public:
}
};
+/// This represents '#pragma omp master taskloop' directive.
+///
+/// \code
+/// #pragma omp master taskloop private(a,b) grainsize(val) num_tasks(num)
+/// \endcode
+/// In this example directive '#pragma omp master taskloop' has clauses
+/// 'private' with the variables 'a' and 'b', 'grainsize' with expression 'val'
+/// and 'num_tasks' with expression 'num'.
+///
+class OMPMasterTaskLoopDirective : public OMPLoopDirective {
+ friend class ASTStmtReader;
+ /// Build directive with the given start and end location.
+ ///
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending location of the directive.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ OMPMasterTaskLoopDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, unsigned NumClauses)
+ : OMPLoopDirective(this, OMPMasterTaskLoopDirectiveClass,
+ OMPD_master_taskloop, StartLoc, EndLoc, CollapsedNum,
+ NumClauses) {}
+
+ /// Build an empty directive.
+ ///
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ explicit OMPMasterTaskLoopDirective(unsigned CollapsedNum,
+ unsigned NumClauses)
+ : OMPLoopDirective(this, OMPMasterTaskLoopDirectiveClass,
+ OMPD_master_taskloop, SourceLocation(),
+ SourceLocation(), CollapsedNum, NumClauses) {}
+
+public:
+ /// Creates directive with a list of \a Clauses.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending Location of the directive.
+ /// \param CollapsedNum Number of collapsed loops.
+ /// \param Clauses List of clauses.
+ /// \param AssociatedStmt Statement, associated with the directive.
+ /// \param Exprs Helper expressions for CodeGen.
+ ///
+ static OMPMasterTaskLoopDirective *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt, const HelperExprs &Exprs);
+
+ /// Creates an empty directive with the place
+ /// for \a NumClauses clauses.
+ ///
+ /// \param C AST context.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ static OMPMasterTaskLoopDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum,
+ EmptyShell);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPMasterTaskLoopDirectiveClass;
+ }
+};
+
+/// This represents '#pragma omp master taskloop simd' directive.
+///
+/// \code
+/// #pragma omp master taskloop simd private(a,b) grainsize(val) num_tasks(num)
+/// \endcode
+/// In this example directive '#pragma omp master taskloop simd' has clauses
+/// 'private' with the variables 'a' and 'b', 'grainsize' with expression 'val'
+/// and 'num_tasks' with expression 'num'.
+///
+class OMPMasterTaskLoopSimdDirective : public OMPLoopDirective {
+ friend class ASTStmtReader;
+ /// Build directive with the given start and end location.
+ ///
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending location of the directive.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ OMPMasterTaskLoopSimdDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, unsigned NumClauses)
+ : OMPLoopDirective(this, OMPMasterTaskLoopSimdDirectiveClass,
+ OMPD_master_taskloop_simd, StartLoc, EndLoc,
+ CollapsedNum, NumClauses) {}
+
+ /// Build an empty directive.
+ ///
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ explicit OMPMasterTaskLoopSimdDirective(unsigned CollapsedNum,
+ unsigned NumClauses)
+ : OMPLoopDirective(this, OMPMasterTaskLoopSimdDirectiveClass,
+ OMPD_master_taskloop_simd, SourceLocation(),
+ SourceLocation(), CollapsedNum, NumClauses) {}
+
+public:
+ /// Creates directive with a list of \p Clauses.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending Location of the directive.
+ /// \param CollapsedNum Number of collapsed loops.
+ /// \param Clauses List of clauses.
+ /// \param AssociatedStmt Statement, associated with the directive.
+ /// \param Exprs Helper expressions for CodeGen.
+ ///
+ static OMPMasterTaskLoopSimdDirective *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt, const HelperExprs &Exprs);
+
+ /// Creates an empty directive with the place for \p NumClauses clauses.
+ ///
+ /// \param C AST context.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ static OMPMasterTaskLoopSimdDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum,
+ EmptyShell);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPMasterTaskLoopSimdDirectiveClass;
+ }
+};
+
+/// This represents '#pragma omp parallel master taskloop' directive.
+///
+/// \code
+/// #pragma omp parallel master taskloop private(a,b) grainsize(val)
+/// num_tasks(num)
+/// \endcode
+/// In this example directive '#pragma omp parallel master taskloop' has clauses
+/// 'private' with the variables 'a' and 'b', 'grainsize' with expression 'val'
+/// and 'num_tasks' with expression 'num'.
+///
+class OMPParallelMasterTaskLoopDirective : public OMPLoopDirective {
+ friend class ASTStmtReader;
+ /// Build directive with the given start and end location.
+ ///
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending location of the directive.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ OMPParallelMasterTaskLoopDirective(SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ unsigned CollapsedNum, unsigned NumClauses)
+ : OMPLoopDirective(this, OMPParallelMasterTaskLoopDirectiveClass,
+ OMPD_parallel_master_taskloop, StartLoc, EndLoc,
+ CollapsedNum, NumClauses) {}
+
+ /// Build an empty directive.
+ ///
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ explicit OMPParallelMasterTaskLoopDirective(unsigned CollapsedNum,
+ unsigned NumClauses)
+ : OMPLoopDirective(this, OMPParallelMasterTaskLoopDirectiveClass,
+ OMPD_parallel_master_taskloop, SourceLocation(),
+ SourceLocation(), CollapsedNum, NumClauses) {}
+
+public:
+ /// Creates directive with a list of \a Clauses.
+ ///
+ /// \param C AST context.
+ /// \param StartLoc Starting location of the directive kind.
+ /// \param EndLoc Ending Location of the directive.
+ /// \param CollapsedNum Number of collapsed loops.
+ /// \param Clauses List of clauses.
+ /// \param AssociatedStmt Statement, associated with the directive.
+ /// \param Exprs Helper expressions for CodeGen.
+ ///
+ static OMPParallelMasterTaskLoopDirective *
+ Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt, const HelperExprs &Exprs);
+
+ /// Creates an empty directive with the place
+ /// for \a NumClauses clauses.
+ ///
+ /// \param C AST context.
+ /// \param CollapsedNum Number of collapsed nested loops.
+ /// \param NumClauses Number of clauses.
+ ///
+ static OMPParallelMasterTaskLoopDirective *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum,
+ EmptyShell);
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == OMPParallelMasterTaskLoopDirectiveClass;
+ }
+};
+
/// This represents '#pragma omp distribute' directive.
///
/// \code
diff --git a/include/clang/AST/TextNodeDumper.h b/include/clang/AST/TextNodeDumper.h
index 4c2d0710963b..0ff5a614a864 100644
--- a/include/clang/AST/TextNodeDumper.h
+++ b/include/clang/AST/TextNodeDumper.h
@@ -146,8 +146,6 @@ class TextNodeDumper
const comments::CommandTraits *Traits;
- const ASTContext *Context;
-
const char *getCommandName(unsigned CommandID);
public:
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 584655fe789e..c9238e952101 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -126,7 +126,7 @@ using CanQualType = CanQual<Type>;
// Provide forward declarations for all of the *Type classes.
#define TYPE(Class, Base) class Class##Type;
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
/// The collection of all-type qualifiers we support.
/// Clang supports five independent qualifiers:
@@ -972,6 +972,9 @@ public:
friend bool operator!=(const QualType &LHS, const QualType &RHS) {
return LHS.Value != RHS.Value;
}
+ friend bool operator<(const QualType &LHS, const QualType &RHS) {
+ return LHS.Value < RHS.Value;
+ }
static std::string getAsString(SplitQualType split,
const PrintingPolicy &Policy) {
@@ -1434,10 +1437,9 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
public:
enum TypeClass {
#define TYPE(Class, Base) Class,
-#define LAST_TYPE(Class) TypeLast = Class,
+#define LAST_TYPE(Class) TypeLast = Class
#define ABSTRACT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
- TagFirst = Record, TagLast = Enum
+#include "clang/AST/TypeNodes.inc"
};
private:
@@ -1511,6 +1513,15 @@ protected:
unsigned SizeModifier : 3;
};
+ class ConstantArrayTypeBitfields {
+ friend class ConstantArrayType;
+
+ unsigned : NumTypeBits + 3 + 3;
+
+ /// Whether we have a stored size expression.
+ unsigned HasStoredSizeExpr : 1;
+ };
+
class BuiltinTypeBitfields {
friend class BuiltinType;
@@ -1732,6 +1743,7 @@ protected:
union {
TypeBitfields TypeBits;
ArrayTypeBitfields ArrayTypeBits;
+ ConstantArrayTypeBitfields ConstantArrayTypeBits;
AttributedTypeBitfields AttributedTypeBits;
AutoTypeBitfields AutoTypeBits;
BuiltinTypeBitfields BuiltinTypeBits;
@@ -2053,6 +2065,7 @@ public:
bool isCARCBridgableType() const;
bool isTemplateTypeParmType() const; // C++ template type parameter
bool isNullPtrType() const; // C++11 std::nullptr_t
+ bool isNothrowT() const; // C++ std::nothrow_t
bool isAlignValT() const; // C++17 std::align_val_t
bool isStdByteType() const; // C++17 std::byte
bool isAtomicType() const; // C11 _Atomic()
@@ -2416,7 +2429,7 @@ template <> inline const Class##Type *Type::getAs() const { \
template <> inline const Class##Type *Type::castAs() const { \
return cast<Class##Type>(CanonicalType); \
}
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
/// This class is used for builtin types like 'int'. Builtin
/// types are always canonical and have a literal name field.
@@ -2429,6 +2442,9 @@ public:
// OpenCL extension types
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) Id,
#include "clang/Basic/OpenCLExtensionTypes.def"
+// SVE Types
+#define SVE_TYPE(Name, Id, SingletonId) Id,
+#include "clang/Basic/AArch64SVEACLETypes.def"
// All other builtin types
#define BUILTIN_TYPE(Id, SingletonId) Id,
#define LAST_BUILTIN_TYPE(Id) LastKind = Id
@@ -2858,22 +2874,8 @@ private:
protected:
friend class ASTContext; // ASTContext creates these.
- // C++ [temp.dep.type]p1:
- // A type is dependent if it is...
- // - an array type constructed from any dependent type or whose
- // size is specified by a constant expression that is
- // value-dependent,
- ArrayType(TypeClass tc, QualType et, QualType can,
- ArraySizeModifier sm, unsigned tq,
- bool ContainsUnexpandedParameterPack)
- : Type(tc, can, et->isDependentType() || tc == DependentSizedArray,
- et->isInstantiationDependentType() || tc == DependentSizedArray,
- (tc == VariableArray || et->isVariablyModifiedType()),
- ContainsUnexpandedParameterPack),
- ElementType(et) {
- ArrayTypeBits.IndexTypeQuals = tq;
- ArrayTypeBits.SizeModifier = sm;
- }
+ ArrayType(TypeClass tc, QualType et, QualType can, ArraySizeModifier sm,
+ unsigned tq, const Expr *sz = nullptr);
public:
QualType getElementType() const { return ElementType; }
@@ -2901,25 +2903,35 @@ public:
/// Represents the canonical version of C arrays with a specified constant size.
/// For example, the canonical type for 'int A[4 + 4*100]' is a
/// ConstantArrayType where the element type is 'int' and the size is 404.
-class ConstantArrayType : public ArrayType {
+class ConstantArrayType final
+ : public ArrayType,
+ private llvm::TrailingObjects<ConstantArrayType, const Expr *> {
+ friend class ASTContext; // ASTContext creates these.
+ friend TrailingObjects;
+
llvm::APInt Size; // Allows us to unique the type.
ConstantArrayType(QualType et, QualType can, const llvm::APInt &size,
- ArraySizeModifier sm, unsigned tq)
- : ArrayType(ConstantArray, et, can, sm, tq,
- et->containsUnexpandedParameterPack()),
- Size(size) {}
-
-protected:
- friend class ASTContext; // ASTContext creates these.
+ const Expr *sz, ArraySizeModifier sm, unsigned tq)
+ : ArrayType(ConstantArray, et, can, sm, tq, sz), Size(size) {
+ ConstantArrayTypeBits.HasStoredSizeExpr = sz != nullptr;
+ if (ConstantArrayTypeBits.HasStoredSizeExpr) {
+ assert(!can.isNull() && "canonical constant array should not have size");
+ *getTrailingObjects<const Expr*>() = sz;
+ }
+ }
- ConstantArrayType(TypeClass tc, QualType et, QualType can,
- const llvm::APInt &size, ArraySizeModifier sm, unsigned tq)
- : ArrayType(tc, et, can, sm, tq, et->containsUnexpandedParameterPack()),
- Size(size) {}
+ unsigned numTrailingObjects(OverloadToken<const Expr*>) const {
+ return ConstantArrayTypeBits.HasStoredSizeExpr;
+ }
public:
const llvm::APInt &getSize() const { return Size; }
+ const Expr *getSizeExpr() const {
+ return ConstantArrayTypeBits.HasStoredSizeExpr
+ ? *getTrailingObjects<const Expr *>()
+ : nullptr;
+ }
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
@@ -2933,19 +2945,15 @@ public:
/// can require, which limits the maximum size of the array.
static unsigned getMaxSizeBits(const ASTContext &Context);
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getElementType(), getSize(),
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) {
+ Profile(ID, Ctx, getElementType(), getSize(), getSizeExpr(),
getSizeModifier(), getIndexTypeCVRQualifiers());
}
- static void Profile(llvm::FoldingSetNodeID &ID, QualType ET,
- const llvm::APInt &ArraySize, ArraySizeModifier SizeMod,
- unsigned TypeQuals) {
- ID.AddPointer(ET.getAsOpaquePtr());
- ID.AddInteger(ArraySize.getZExtValue());
- ID.AddInteger(SizeMod);
- ID.AddInteger(TypeQuals);
- }
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx,
+ QualType ET, const llvm::APInt &ArraySize,
+ const Expr *SizeExpr, ArraySizeModifier SizeMod,
+ unsigned TypeQuals);
static bool classof(const Type *T) {
return T->getTypeClass() == ConstantArray;
@@ -2960,8 +2968,7 @@ class IncompleteArrayType : public ArrayType {
IncompleteArrayType(QualType et, QualType can,
ArraySizeModifier sm, unsigned tq)
- : ArrayType(IncompleteArray, et, can, sm, tq,
- et->containsUnexpandedParameterPack()) {}
+ : ArrayType(IncompleteArray, et, can, sm, tq) {}
public:
friend class StmtIteratorBase;
@@ -3013,8 +3020,7 @@ class VariableArrayType : public ArrayType {
VariableArrayType(QualType et, QualType can, Expr *e,
ArraySizeModifier sm, unsigned tq,
SourceRange brackets)
- : ArrayType(VariableArray, et, can, sm, tq,
- et->containsUnexpandedParameterPack()),
+ : ArrayType(VariableArray, et, can, sm, tq, e),
SizeExpr((Stmt*) e), Brackets(brackets) {}
public:
@@ -4429,7 +4435,7 @@ public:
bool isBeingDefined() const;
static bool classof(const Type *T) {
- return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast;
+ return T->getTypeClass() == Enum || T->getTypeClass() == Record;
}
};
@@ -5563,7 +5569,7 @@ class ObjCTypeParamType : public Type,
public:
bool isSugared() const { return true; }
- QualType desugar() const { return getCanonicalTypeInternal(); }
+ QualType desugar() const;
static bool classof(const Type *T) {
return T->getTypeClass() == ObjCTypeParam;
@@ -6347,6 +6353,7 @@ inline bool QualType::isCForbiddenLValueType() const {
/// \returns True for types specified in C++0x [basic.fundamental].
inline bool Type::isFundamentalType() const {
return isVoidType() ||
+ isNullPtrType() ||
// FIXME: It's really annoying that we don't have an
// 'isArithmeticType()' which agrees with the standard definition.
(isArithmeticType() && !isEnumeralType());
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 40d17f991f1f..f305680d775c 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -106,7 +106,7 @@ public:
#define ABSTRACT_TYPE(Class, Base)
#define TYPE(Class, Base) \
Class = Type::Class,
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
Qualified
};
diff --git a/include/clang/AST/TypeLocNodes.def b/include/clang/AST/TypeLocNodes.def
index c0dfe150d6cc..81448c7e7ce5 100644
--- a/include/clang/AST/TypeLocNodes.def
+++ b/include/clang/AST/TypeLocNodes.def
@@ -31,7 +31,7 @@
TYPELOC(Qualified, TypeLoc)
#define TYPE(Class, Base) UNQUAL_TYPELOC(Class, Base##Loc)
#define ABSTRACT_TYPE(Class, Base) ABSTRACT_TYPELOC(Class, Base##Loc)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
#undef DECLARATOR_TYPELOC
#undef TYPESPEC_TYPELOC
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
deleted file mode 100644
index 58a5f880cbe6..000000000000
--- a/include/clang/AST/TypeNodes.def
+++ /dev/null
@@ -1,135 +0,0 @@
-//===-- TypeNodes.def - Metadata about Type AST nodes -----------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the AST type info database. Each type node is
-// enumerated by providing its name (e.g., "Builtin" or "Enum") and
-// base class (e.g., "Type" or "TagType"). Depending on where in the
-// abstract syntax tree the type will show up, the enumeration uses
-// one of five different macros:
-//
-// TYPE(Class, Base) - A type that can show up anywhere in the AST,
-// and might be dependent, canonical, or non-canonical. All clients
-// will need to understand these types.
-//
-// ABSTRACT_TYPE(Class, Base) - An abstract class that shows up in
-// the type hierarchy but has no concrete instances.
-//
-// NON_CANONICAL_TYPE(Class, Base) - A type that can show up
-// anywhere in the AST but will never be a part of a canonical
-// type. Clients that only need to deal with canonical types
-// (ignoring, e.g., typedefs and other type aliases used for
-// pretty-printing) can ignore these types.
-//
-// DEPENDENT_TYPE(Class, Base) - A type that will only show up
-// within a C++ template that has not been instantiated, e.g., a
-// type that is always dependent. Clients that do not need to deal
-// with uninstantiated C++ templates can ignore these types.
-//
-// NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) - A type that
-// is non-canonical unless it is dependent. Defaults to TYPE because
-// it is neither reliably dependent nor reliably non-canonical.
-//
-// There is a sixth macro, independent of the others. Most clients
-// will not need to use it.
-//
-// LEAF_TYPE(Class) - A type that never has inner types. Clients
-// which can operate on such types more efficiently may wish to do so.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef ABSTRACT_TYPE
-# define ABSTRACT_TYPE(Class, Base) TYPE(Class, Base)
-#endif
-
-#ifndef NON_CANONICAL_TYPE
-# define NON_CANONICAL_TYPE(Class, Base) TYPE(Class, Base)
-#endif
-
-#ifndef DEPENDENT_TYPE
-# define DEPENDENT_TYPE(Class, Base) TYPE(Class, Base)
-#endif
-
-#ifndef NON_CANONICAL_UNLESS_DEPENDENT_TYPE
-# define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) TYPE(Class, Base)
-#endif
-
-TYPE(Builtin, Type)
-TYPE(Complex, Type)
-TYPE(Pointer, Type)
-TYPE(BlockPointer, Type)
-ABSTRACT_TYPE(Reference, Type)
-TYPE(LValueReference, ReferenceType)
-TYPE(RValueReference, ReferenceType)
-TYPE(MemberPointer, Type)
-ABSTRACT_TYPE(Array, Type)
-TYPE(ConstantArray, ArrayType)
-TYPE(IncompleteArray, ArrayType)
-TYPE(VariableArray, ArrayType)
-DEPENDENT_TYPE(DependentSizedArray, ArrayType)
-DEPENDENT_TYPE(DependentSizedExtVector, Type)
-DEPENDENT_TYPE(DependentAddressSpace, Type)
-TYPE(Vector, Type)
-DEPENDENT_TYPE(DependentVector, Type)
-TYPE(ExtVector, VectorType)
-ABSTRACT_TYPE(Function, Type)
-TYPE(FunctionProto, FunctionType)
-TYPE(FunctionNoProto, FunctionType)
-DEPENDENT_TYPE(UnresolvedUsing, Type)
-NON_CANONICAL_TYPE(Paren, Type)
-NON_CANONICAL_TYPE(Typedef, Type)
-NON_CANONICAL_TYPE(MacroQualified, Type)
-NON_CANONICAL_TYPE(Adjusted, Type)
-NON_CANONICAL_TYPE(Decayed, AdjustedType)
-NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOfExpr, Type)
-NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOf, Type)
-NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Decltype, Type)
-NON_CANONICAL_UNLESS_DEPENDENT_TYPE(UnaryTransform, Type)
-ABSTRACT_TYPE(Tag, Type)
-TYPE(Record, TagType)
-TYPE(Enum, TagType)
-NON_CANONICAL_TYPE(Elaborated, Type)
-NON_CANONICAL_TYPE(Attributed, Type)
-DEPENDENT_TYPE(TemplateTypeParm, Type)
-NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type)
-DEPENDENT_TYPE(SubstTemplateTypeParmPack, Type)
-NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type)
-ABSTRACT_TYPE(Deduced, Type)
-TYPE(Auto, DeducedType)
-TYPE(DeducedTemplateSpecialization, DeducedType)
-DEPENDENT_TYPE(InjectedClassName, Type)
-DEPENDENT_TYPE(DependentName, Type)
-DEPENDENT_TYPE(DependentTemplateSpecialization, Type)
-NON_CANONICAL_UNLESS_DEPENDENT_TYPE(PackExpansion, Type)
-NON_CANONICAL_TYPE(ObjCTypeParam, Type)
-TYPE(ObjCObject, Type)
-TYPE(ObjCInterface, ObjCObjectType)
-TYPE(ObjCObjectPointer, Type)
-TYPE(Pipe, Type)
-TYPE(Atomic, Type)
-
-#ifdef LAST_TYPE
-LAST_TYPE(Atomic)
-#undef LAST_TYPE
-#endif
-
-// These types are always leaves in the type hierarchy.
-#ifdef LEAF_TYPE
-LEAF_TYPE(Enum)
-LEAF_TYPE(Builtin)
-LEAF_TYPE(Record)
-LEAF_TYPE(InjectedClassName)
-LEAF_TYPE(ObjCInterface)
-LEAF_TYPE(TemplateTypeParm)
-#undef LEAF_TYPE
-#endif
-
-#undef NON_CANONICAL_UNLESS_DEPENDENT_TYPE
-#undef DEPENDENT_TYPE
-#undef NON_CANONICAL_TYPE
-#undef ABSTRACT_TYPE
-#undef TYPE
diff --git a/include/clang/AST/TypeVisitor.h b/include/clang/AST/TypeVisitor.h
index 8930ec853949..17301835fb18 100644
--- a/include/clang/AST/TypeVisitor.h
+++ b/include/clang/AST/TypeVisitor.h
@@ -70,7 +70,7 @@ public:
switch (T->getTypeClass()) {
#define ABSTRACT_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) case Type::CLASS: DISPATCH(CLASS##Type);
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
llvm_unreachable("Unknown type class!");
}
@@ -80,7 +80,7 @@ public:
#define TYPE(CLASS, PARENT) RetTy Visit##CLASS##Type(const CLASS##Type *T) { \
DISPATCH(PARENT); \
}
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
/// Method called if \c ImpClass doesn't provide specific handler
/// for some type class.
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 063d8217d9aa..e34b31cbda88 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -19,15 +19,15 @@
//
// For more complicated match expressions we're often interested in accessing
// multiple parts of the matched AST nodes once a match is found. In that case,
-// use the id(...) matcher around the match expressions that match the nodes
-// you want to access.
+// call `.bind("name")` on match expressions that match the nodes you want to
+// access.
//
// For example, when we're interested in child classes of a certain class, we
// would write:
-// cxxRecordDecl(hasName("MyClass"), has(id("child", recordDecl())))
+// cxxRecordDecl(hasName("MyClass"), has(recordDecl().bind("child")))
// When the match is found via the MatchFinder, a user provided callback will
// be called with a BoundNodes instance that contains a mapping from the
-// strings that we provided for the id(...) calls to the nodes that were
+// strings that we provided for the `.bind()` calls to the nodes that were
// matched.
// In the given example, each time our matcher finds a match we get a callback
// where "child" is bound to the RecordDecl node of the matching child
@@ -131,15 +131,6 @@ private:
internal::BoundNodesMap MyBoundNodes;
};
-/// If the provided matcher matches a node, binds the node to \c ID.
-///
-/// FIXME: Do we want to support this now that we have bind()?
-template <typename T>
-internal::Matcher<T> id(StringRef ID,
- const internal::BindableMatcher<T> &InnerMatcher) {
- return InnerMatcher.bind(ID);
-}
-
/// Types of matchers for the top-level classes in the AST class
/// hierarchy.
/// @{
@@ -2611,8 +2602,9 @@ hasOverloadedOperatorName(StringRef Name) {
AST_POLYMORPHIC_SUPPORTED_TYPES(CXXOperatorCallExpr, FunctionDecl)>(Name);
}
-/// Matches C++ classes that are directly or indirectly derived from
-/// a class matching \c Base.
+/// Matches C++ classes that are directly or indirectly derived from a class
+/// matching \c Base, or Objective-C classes that directly or indirectly
+/// subclass a class matching \c Base.
///
/// Note that a class is not considered to be derived from itself.
///
@@ -2632,33 +2624,128 @@ hasOverloadedOperatorName(StringRef Name) {
/// typedef Foo X;
/// class Bar : public Foo {}; // derived from a type that X is a typedef of
/// \endcode
-AST_MATCHER_P(CXXRecordDecl, isDerivedFrom,
- internal::Matcher<NamedDecl>, Base) {
- return Finder->classIsDerivedFrom(&Node, Base, Builder);
+///
+/// In the following example, Bar matches isDerivedFrom(hasName("NSObject"))
+/// \code
+/// @interface NSObject @end
+/// @interface Bar : NSObject @end
+/// \endcode
+///
+/// Usable as: Matcher<CXXRecordDecl>, Matcher<ObjCInterfaceDecl>
+AST_POLYMORPHIC_MATCHER_P(
+ isDerivedFrom,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, ObjCInterfaceDecl),
+ internal::Matcher<NamedDecl>, Base) {
+ // Check if the node is a C++ struct/union/class.
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(&Node))
+ return Finder->classIsDerivedFrom(RD, Base, Builder, /*Directly=*/false);
+
+ // The node must be an Objective-C class.
+ const auto *InterfaceDecl = cast<ObjCInterfaceDecl>(&Node);
+ return Finder->objcClassIsDerivedFrom(InterfaceDecl, Base, Builder,
+ /*Directly=*/false);
}
/// Overloaded method as shortcut for \c isDerivedFrom(hasName(...)).
-AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDerivedFrom, std::string, BaseName, 1) {
- assert(!BaseName.empty());
- return isDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+ isDerivedFrom,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, ObjCInterfaceDecl),
+ std::string, BaseName, 1) {
+ if (BaseName.empty())
+ return false;
+
+ const auto M = isDerivedFrom(hasName(BaseName));
+
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(&Node))
+ return Matcher<CXXRecordDecl>(M).matches(*RD, Finder, Builder);
+
+ const auto *InterfaceDecl = cast<ObjCInterfaceDecl>(&Node);
+ return Matcher<ObjCInterfaceDecl>(M).matches(*InterfaceDecl, Finder, Builder);
}
/// Similar to \c isDerivedFrom(), but also matches classes that directly
/// match \c Base.
-AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom,
- internal::Matcher<NamedDecl>, Base, 0) {
- return Matcher<CXXRecordDecl>(anyOf(Base, isDerivedFrom(Base)))
- .matches(Node, Finder, Builder);
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+ isSameOrDerivedFrom,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, ObjCInterfaceDecl),
+ internal::Matcher<NamedDecl>, Base, 0) {
+ const auto M = anyOf(Base, isDerivedFrom(Base));
+
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(&Node))
+ return Matcher<CXXRecordDecl>(M).matches(*RD, Finder, Builder);
+
+ const auto *InterfaceDecl = cast<ObjCInterfaceDecl>(&Node);
+ return Matcher<ObjCInterfaceDecl>(M).matches(*InterfaceDecl, Finder, Builder);
}
/// Overloaded method as shortcut for
/// \c isSameOrDerivedFrom(hasName(...)).
-AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, std::string,
- BaseName, 1) {
- assert(!BaseName.empty());
- return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+ isSameOrDerivedFrom,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, ObjCInterfaceDecl),
+ std::string, BaseName, 1) {
+ if (BaseName.empty())
+ return false;
+
+ const auto M = isSameOrDerivedFrom(hasName(BaseName));
+
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(&Node))
+ return Matcher<CXXRecordDecl>(M).matches(*RD, Finder, Builder);
+
+ const auto *InterfaceDecl = cast<ObjCInterfaceDecl>(&Node);
+ return Matcher<ObjCInterfaceDecl>(M).matches(*InterfaceDecl, Finder, Builder);
}
+/// Matches C++ or Objective-C classes that are directly derived from a class
+/// matching \c Base.
+///
+/// Note that a class is not considered to be derived from itself.
+///
+/// Example matches Y, C (Base == hasName("X"))
+/// \code
+/// class X;
+/// class Y : public X {}; // directly derived
+/// class Z : public Y {}; // indirectly derived
+/// typedef X A;
+/// typedef A B;
+/// class C : public B {}; // derived from a typedef of X
+/// \endcode
+///
+/// In the following example, Bar matches isDerivedFrom(hasName("X")):
+/// \code
+/// class Foo;
+/// typedef Foo X;
+/// class Bar : public Foo {}; // derived from a type that X is a typedef of
+/// \endcode
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+ isDirectlyDerivedFrom,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, ObjCInterfaceDecl),
+ internal::Matcher<NamedDecl>, Base, 0) {
+ // Check if the node is a C++ struct/union/class.
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(&Node))
+ return Finder->classIsDerivedFrom(RD, Base, Builder, /*Directly=*/true);
+
+ // The node must be an Objective-C class.
+ const auto *InterfaceDecl = cast<ObjCInterfaceDecl>(&Node);
+ return Finder->objcClassIsDerivedFrom(InterfaceDecl, Base, Builder,
+ /*Directly=*/true);
+}
+
+/// Overloaded method as shortcut for \c isDirectlyDerivedFrom(hasName(...)).
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+ isDirectlyDerivedFrom,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, ObjCInterfaceDecl),
+ std::string, BaseName, 1) {
+ if (BaseName.empty())
+ return false;
+ const auto M = isDirectlyDerivedFrom(hasName(BaseName));
+
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(&Node))
+ return Matcher<CXXRecordDecl>(M).matches(*RD, Finder, Builder);
+
+ const auto *InterfaceDecl = cast<ObjCInterfaceDecl>(&Node);
+ return Matcher<ObjCInterfaceDecl>(M).matches(*InterfaceDecl, Finder, Builder);
+}
/// Matches the first method of a class or struct that satisfies \c
/// InnerMatcher.
///
@@ -6358,10 +6445,9 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CUDAKernelCallExpr>
/// expr(nullPointerConstant())
/// matches the initializer for v1, v2, v3, cp, and ip. Does not match the
/// initializer for i.
-AST_MATCHER_FUNCTION(internal::Matcher<Expr>, nullPointerConstant) {
- return anyOf(
- gnuNullExpr(), cxxNullPtrLiteralExpr(),
- integerLiteral(equals(0), hasParent(expr(hasType(pointerType())))));
+AST_MATCHER(Expr, nullPointerConstant) {
+ return Node.isNullPointerConstant(Finder->getASTContext(),
+ Expr::NPC_ValueDependentIsNull);
}
/// Matches declaration of the function the statement belongs to
@@ -6375,7 +6461,7 @@ AST_MATCHER_FUNCTION(internal::Matcher<Expr>, nullPointerConstant) {
/// \endcode
/// returnStmt(forFunction(hasName("operator=")))
/// matches 'return *this'
-/// but does match 'return > 0'
+/// but does not match 'return v > 0'
AST_MATCHER_P(Stmt, forFunction, internal::Matcher<FunctionDecl>,
InnerMatcher) {
const auto &Parents = Finder->getASTContext().getParents(Node);
@@ -6498,14 +6584,15 @@ AST_MATCHER(FunctionDecl, hasTrailingReturn) {
}
/// Matches expressions that match InnerMatcher that are possibly wrapped in an
-/// elidable constructor.
+/// elidable constructor and other corresponding bookkeeping nodes.
///
-/// In C++17 copy elidable constructors are no longer being
-/// generated in the AST as it is not permitted by the standard. They are
-/// however part of the AST in C++14 and earlier. Therefore, to write a matcher
-/// that works in all language modes, the matcher has to skip elidable
-/// constructor AST nodes if they appear in the AST. This matcher can be used to
-/// skip those elidable constructors.
+/// In C++17, elidable copy constructors are no longer being generated in the
+/// AST as it is not permitted by the standard. They are, however, part of the
+/// AST in C++14 and earlier. So, a matcher must abstract over these differences
+/// to work in all language modes. This matcher skips elidable constructor-call
+/// AST nodes, `ExprWithCleanups` nodes wrapping elidable constructor-calls and
+/// various implicit nodes inside the constructor calls, all of which will not
+/// appear in the C++17 AST.
///
/// Given
///
@@ -6517,13 +6604,20 @@ AST_MATCHER(FunctionDecl, hasTrailingReturn) {
/// }
/// \endcode
///
-/// ``varDecl(hasInitializer(any(
-/// ignoringElidableConstructorCall(callExpr()),
-/// exprWithCleanups(ignoringElidableConstructorCall(callExpr()))))``
-/// matches ``H D = G()``
+/// ``varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr())))``
+/// matches ``H D = G()`` in C++11 through C++17 (and beyond).
AST_MATCHER_P(Expr, ignoringElidableConstructorCall,
ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
- if (const auto *CtorExpr = dyn_cast<CXXConstructExpr>(&Node)) {
+ // E tracks the node that we are examining.
+ const Expr *E = &Node;
+ // If present, remove an outer `ExprWithCleanups` corresponding to the
+ // underlying `CXXConstructExpr`. This check won't cover all cases of added
+ // `ExprWithCleanups` corresponding to `CXXConstructExpr` nodes (because the
+ // EWC is placed on the outermost node of the expression, which this may not
+ // be), but, it still improves the coverage of this matcher.
+ if (const auto *CleanupsExpr = dyn_cast<ExprWithCleanups>(&Node))
+ E = CleanupsExpr->getSubExpr();
+ if (const auto *CtorExpr = dyn_cast<CXXConstructExpr>(E)) {
if (CtorExpr->isElidable()) {
if (const auto *MaterializeTemp =
dyn_cast<MaterializeTemporaryExpr>(CtorExpr->getArg(0))) {
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index b1bb0bfa3218..e9fa920b6bce 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -183,7 +183,8 @@ public:
/// Note that we're using std::map here, as for memoization:
/// - we need a comparison operator
/// - we need an assignment operator
- using IDToNodeMap = std::map<std::string, ast_type_traits::DynTypedNode>;
+ using IDToNodeMap =
+ std::map<std::string, ast_type_traits::DynTypedNode, std::less<>>;
const IDToNodeMap &getMap() const {
return NodeMap;
@@ -971,13 +972,23 @@ public:
virtual ~ASTMatchFinder() = default;
- /// Returns true if the given class is directly or indirectly derived
+ /// Returns true if the given C++ class is directly or indirectly derived
/// from a base type matching \c base.
///
- /// A class is considered to be also derived from itself.
+ /// A class is not considered to be derived from itself.
virtual bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
const Matcher<NamedDecl> &Base,
- BoundNodesTreeBuilder *Builder) = 0;
+ BoundNodesTreeBuilder *Builder,
+ bool Directly) = 0;
+
+ /// Returns true if the given Objective-C class is directly or indirectly
+ /// derived from a base class matching \c base.
+ ///
+ /// A class is not considered to be derived from itself.
+ virtual bool objcClassIsDerivedFrom(const ObjCInterfaceDecl *Declaration,
+ const Matcher<NamedDecl> &Base,
+ BoundNodesTreeBuilder *Builder,
+ bool Directly) = 0;
template <typename T>
bool matchesChildOf(const T &Node, const DynTypedMatcher &Matcher,
@@ -1315,7 +1326,7 @@ class ForEachMatcher : public WrapperMatcherInterface<T> {
///
/// Input matchers can have any type (including other polymorphic matcher
/// types), and the actual Matcher<T> is generated on demand with an implicit
-/// coversion operator.
+/// conversion operator.
template <typename... Ps> class VariadicOperatorMatcher {
public:
VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op, Ps &&... Params)
@@ -1324,14 +1335,14 @@ public:
template <typename T> operator Matcher<T>() const {
return DynTypedMatcher::constructVariadic(
Op, ast_type_traits::ASTNodeKind::getFromNodeKind<T>(),
- getMatchers<T>(llvm::index_sequence_for<Ps...>()))
+ getMatchers<T>(std::index_sequence_for<Ps...>()))
.template unconditionalConvertTo<T>();
}
private:
// Helper method to unpack the tuple into a vector.
template <typename T, std::size_t... Is>
- std::vector<DynTypedMatcher> getMatchers(llvm::index_sequence<Is...>) const {
+ std::vector<DynTypedMatcher> getMatchers(std::index_sequence<Is...>) const {
return {Matcher<T>(std::get<Is>(Params))...};
}
diff --git a/include/clang/Analysis/AnalysisDeclContext.h b/include/clang/Analysis/AnalysisDeclContext.h
index 1961d571e9e1..9faa78cde89c 100644
--- a/include/clang/Analysis/AnalysisDeclContext.h
+++ b/include/clang/Analysis/AnalysisDeclContext.h
@@ -183,9 +183,8 @@ public:
const ImplicitParamDecl *getSelfDecl() const;
const StackFrameContext *getStackFrame(LocationContext const *Parent,
- const Stmt *S,
- const CFGBlock *Blk,
- unsigned Idx);
+ const Stmt *S, const CFGBlock *Blk,
+ unsigned BlockCount, unsigned Idx);
const BlockInvocationContext *
getBlockInvocationContext(const LocationContext *parent,
@@ -258,7 +257,7 @@ public:
return getAnalysisDeclContext()->getAnalysis<T>();
}
- ParentMap &getParentMap() const {
+ const ParentMap &getParentMap() const {
return getAnalysisDeclContext()->getParentMap();
}
@@ -303,15 +302,19 @@ class StackFrameContext : public LocationContext {
// The parent block of the callsite.
const CFGBlock *Block;
+ // The number of times the 'Block' has been visited.
+ // It allows discriminating between stack frames of the same call that is
+ // called multiple times in a loop.
+ const unsigned BlockCount;
+
// The index of the callsite in the CFGBlock.
- unsigned Index;
+ const unsigned Index;
StackFrameContext(AnalysisDeclContext *ctx, const LocationContext *parent,
- const Stmt *s, const CFGBlock *blk,
- unsigned idx,
- int64_t ID)
- : LocationContext(StackFrame, ctx, parent, ID), CallSite(s),
- Block(blk), Index(idx) {}
+ const Stmt *s, const CFGBlock *blk, unsigned blockCount,
+ unsigned idx, int64_t ID)
+ : LocationContext(StackFrame, ctx, parent, ID), CallSite(s), Block(blk),
+ BlockCount(blockCount), Index(idx) {}
public:
~StackFrameContext() override = default;
@@ -329,9 +332,10 @@ public:
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx,
const LocationContext *parent, const Stmt *s,
- const CFGBlock *blk, unsigned idx) {
+ const CFGBlock *blk, unsigned blockCount, unsigned idx) {
ProfileCommon(ID, StackFrame, ctx, parent, s);
ID.AddPointer(blk);
+ ID.AddInteger(blockCount);
ID.AddInteger(idx);
}
@@ -410,8 +414,8 @@ public:
const StackFrameContext *getStackFrame(AnalysisDeclContext *ctx,
const LocationContext *parent,
- const Stmt *s,
- const CFGBlock *blk, unsigned idx);
+ const Stmt *s, const CFGBlock *blk,
+ unsigned blockCount, unsigned idx);
const ScopeContext *getScope(AnalysisDeclContext *ctx,
const LocationContext *parent,
@@ -483,26 +487,25 @@ public:
bool synthesizeBodies() const { return SynthesizeBodies; }
const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx,
- LocationContext const *Parent,
- const Stmt *S,
- const CFGBlock *Blk,
- unsigned Idx) {
- return LocContexts.getStackFrame(Ctx, Parent, S, Blk, Idx);
+ const LocationContext *Parent,
+ const Stmt *S, const CFGBlock *Blk,
+ unsigned BlockCount, unsigned Idx) {
+ return LocContexts.getStackFrame(Ctx, Parent, S, Blk, BlockCount, Idx);
}
// Get the top level stack frame.
const StackFrameContext *getStackFrame(const Decl *D) {
return LocContexts.getStackFrame(getContext(D), nullptr, nullptr, nullptr,
- 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);
+ const LocationContext *Parent,
+ const Stmt *S, const CFGBlock *Blk,
+ unsigned BlockCount, unsigned Idx) {
+ return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, BlockCount,
+ Idx);
}
/// Get a reference to {@code BodyFarm} instance.
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index 277b2292e5ea..a8301a0e0063 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -121,6 +121,12 @@ public:
x |= Data1.getInt();
return (Kind) x;
}
+
+ void dumpToStream(llvm::raw_ostream &OS) const;
+
+ void dump() const {
+ dumpToStream(llvm::errs());
+ }
};
class CFGStmt : public CFGElement {
@@ -610,6 +616,153 @@ class CFGBlock {
bool empty() const { return Impl.empty(); }
};
+ /// A convenience class for comparing CFGElements, since methods of CFGBlock
+ /// like operator[] return CFGElements by value. This is practically a wrapper
+ /// around a (CFGBlock, Index) pair.
+ template <bool IsConst> class ElementRefImpl {
+
+ template <bool IsOtherConst> friend class ElementRefImpl;
+
+ using CFGBlockPtr =
+ typename std::conditional<IsConst, const CFGBlock *, CFGBlock *>::type;
+
+ using CFGElementPtr = typename std::conditional<IsConst, const CFGElement *,
+ CFGElement *>::type;
+
+ protected:
+ CFGBlockPtr Parent;
+ size_t Index;
+
+ public:
+ ElementRefImpl(CFGBlockPtr Parent, size_t Index)
+ : Parent(Parent), Index(Index) {}
+
+ template <bool IsOtherConst>
+ ElementRefImpl(ElementRefImpl<IsOtherConst> Other)
+ : ElementRefImpl(Other.Parent, Other.Index) {}
+
+ size_t getIndexInBlock() const { return Index; }
+
+ CFGBlockPtr getParent() { return Parent; }
+ CFGBlockPtr getParent() const { return Parent; }
+
+ bool operator<(ElementRefImpl Other) const {
+ return std::make_pair(Parent, Index) <
+ std::make_pair(Other.Parent, Other.Index);
+ }
+
+ bool operator==(ElementRefImpl Other) const {
+ return Parent == Other.Parent && Index == Other.Index;
+ }
+
+ bool operator!=(ElementRefImpl Other) const { return !(*this == Other); }
+ CFGElement operator*() const { return (*Parent)[Index]; }
+ CFGElementPtr operator->() const { return &*(Parent->begin() + Index); }
+
+ void dumpToStream(llvm::raw_ostream &OS) const {
+ OS << getIndexInBlock() + 1 << ": ";
+ (*this)->dumpToStream(OS);
+ }
+
+ void dump() const {
+ dumpToStream(llvm::errs());
+ }
+ };
+
+ template <bool IsReverse, bool IsConst> class ElementRefIterator {
+
+ template <bool IsOtherReverse, bool IsOtherConst>
+ friend class ElementRefIterator;
+
+ using CFGBlockRef =
+ typename std::conditional<IsConst, const CFGBlock *, CFGBlock *>::type;
+
+ using UnderlayingIteratorTy = typename std::conditional<
+ IsConst,
+ typename std::conditional<IsReverse,
+ ElementList::const_reverse_iterator,
+ ElementList::const_iterator>::type,
+ typename std::conditional<IsReverse, ElementList::reverse_iterator,
+ ElementList::iterator>::type>::type;
+
+ using IteratorTraits = typename std::iterator_traits<UnderlayingIteratorTy>;
+ using ElementRef = typename CFGBlock::ElementRefImpl<IsConst>;
+
+ public:
+ using difference_type = typename IteratorTraits::difference_type;
+ using value_type = ElementRef;
+ using pointer = ElementRef *;
+ using iterator_category = typename IteratorTraits::iterator_category;
+
+ private:
+ CFGBlockRef Parent;
+ UnderlayingIteratorTy Pos;
+
+ public:
+ ElementRefIterator(CFGBlockRef Parent, UnderlayingIteratorTy Pos)
+ : Parent(Parent), Pos(Pos) {}
+
+ template <bool IsOtherConst>
+ ElementRefIterator(ElementRefIterator<false, IsOtherConst> E)
+ : ElementRefIterator(E.Parent, E.Pos.base()) {}
+
+ template <bool IsOtherConst>
+ ElementRefIterator(ElementRefIterator<true, IsOtherConst> E)
+ : ElementRefIterator(E.Parent, llvm::make_reverse_iterator(E.Pos)) {}
+
+ bool operator<(ElementRefIterator Other) const {
+ assert(Parent == Other.Parent);
+ return Pos < Other.Pos;
+ }
+
+ bool operator==(ElementRefIterator Other) const {
+ return Parent == Other.Parent && Pos == Other.Pos;
+ }
+
+ bool operator!=(ElementRefIterator Other) const {
+ return !(*this == Other);
+ }
+
+ private:
+ template <bool IsOtherConst>
+ static size_t
+ getIndexInBlock(CFGBlock::ElementRefIterator<true, IsOtherConst> E) {
+ return E.Parent->size() - (E.Pos - E.Parent->rbegin()) - 1;
+ }
+
+ template <bool IsOtherConst>
+ static size_t
+ getIndexInBlock(CFGBlock::ElementRefIterator<false, IsOtherConst> E) {
+ return E.Pos - E.Parent->begin();
+ }
+
+ public:
+ value_type operator*() { return {Parent, getIndexInBlock(*this)}; }
+
+ difference_type operator-(ElementRefIterator Other) const {
+ return Pos - Other.Pos;
+ }
+
+ ElementRefIterator operator++() {
+ ++this->Pos;
+ return *this;
+ }
+ ElementRefIterator operator++(int) {
+ ElementRefIterator Ret = *this;
+ ++*this;
+ return Ret;
+ }
+ ElementRefIterator operator+(size_t count) {
+ this->Pos += count;
+ return *this;
+ }
+ ElementRefIterator operator-(size_t count) {
+ this->Pos -= count;
+ return *this;
+ }
+ };
+
+public:
/// The set of statements in the basic block.
ElementList Elements;
@@ -715,6 +868,8 @@ public:
using reverse_iterator = ElementList::reverse_iterator;
using const_reverse_iterator = ElementList::const_reverse_iterator;
+ size_t getIndexInCFG() const;
+
CFGElement front() const { return Elements.front(); }
CFGElement back() const { return Elements.back(); }
@@ -728,6 +883,38 @@ public:
const_reverse_iterator rbegin() const { return Elements.rbegin(); }
const_reverse_iterator rend() const { return Elements.rend(); }
+ using CFGElementRef = ElementRefImpl<false>;
+ using ConstCFGElementRef = ElementRefImpl<true>;
+
+ using ref_iterator = ElementRefIterator<false, false>;
+ using ref_iterator_range = llvm::iterator_range<ref_iterator>;
+ using const_ref_iterator = ElementRefIterator<false, true>;
+ using const_ref_iterator_range = llvm::iterator_range<const_ref_iterator>;
+
+ using reverse_ref_iterator = ElementRefIterator<true, false>;
+ using reverse_ref_iterator_range = llvm::iterator_range<reverse_ref_iterator>;
+
+ using const_reverse_ref_iterator = ElementRefIterator<true, true>;
+ using const_reverse_ref_iterator_range =
+ llvm::iterator_range<const_reverse_ref_iterator>;
+
+ ref_iterator ref_begin() { return {this, begin()}; }
+ ref_iterator ref_end() { return {this, end()}; }
+ const_ref_iterator ref_begin() const { return {this, begin()}; }
+ const_ref_iterator ref_end() const { return {this, end()}; }
+
+ reverse_ref_iterator rref_begin() { return {this, rbegin()}; }
+ reverse_ref_iterator rref_end() { return {this, rend()}; }
+ const_reverse_ref_iterator rref_begin() const { return {this, rbegin()}; }
+ const_reverse_ref_iterator rref_end() const { return {this, rend()}; }
+
+ ref_iterator_range refs() { return {ref_begin(), ref_end()}; }
+ const_ref_iterator_range refs() const { return {ref_begin(), ref_end()}; }
+ reverse_ref_iterator_range rrefs() { return {rref_begin(), rref_end()}; }
+ const_reverse_ref_iterator_range rrefs() const {
+ return {rref_begin(), rref_end()};
+ }
+
unsigned size() const { return Elements.size(); }
bool empty() const { return Elements.empty(); }
@@ -855,6 +1042,10 @@ public:
void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; }
void setHasNoReturnElement() { HasNoReturnElement = true; }
+ /// Returns true if the block would eventually end with a sink (a noreturn
+ /// node).
+ bool isInevitablySinking() const;
+
CFGTerminator getTerminator() const { return Terminator; }
Stmt *getTerminatorStmt() { return Terminator.getStmt(); }
@@ -894,7 +1085,7 @@ public:
void printTerminator(raw_ostream &OS, const LangOptions &LO) const;
void printTerminatorJson(raw_ostream &Out, const LangOptions &LO,
bool AddQuotes) const;
-
+
void printAsOperand(raw_ostream &OS, bool /*PrintType*/) {
OS << "BB#" << getBlockID();
}
@@ -1010,7 +1201,6 @@ public:
*I = CFGScopeEnd(VD, S);
return ++I;
}
-
};
/// CFGCallback defines methods that should be called when a logical
@@ -1023,6 +1213,7 @@ public:
virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {}
virtual void compareBitwiseEquality(const BinaryOperator *B,
bool isAlwaysTrue) {}
+ virtual void compareBitwiseOr(const BinaryOperator *B) {}
};
/// Represents a source-level, intra-procedural CFG that represents the
diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h
index 49c04490fed2..dae2b58ffc10 100644
--- a/include/clang/Analysis/CallGraph.h
+++ b/include/clang/Analysis/CallGraph.h
@@ -131,6 +131,7 @@ public:
bool shouldWalkTypesOfTypeLocs() const { return false; }
bool shouldVisitTemplateInstantiations() const { return true; }
+ bool shouldVisitImplicitCode() const { return true; }
private:
/// Add the given declaration to the call graph.
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/Analysis/PathDiagnostic.h
index 5230742a4aa4..6730057cf0ad 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/Analysis/PathDiagnostic.h
@@ -52,11 +52,6 @@ class SourceManager;
namespace ento {
-class ExplodedNode;
-class SymExpr;
-
-using SymbolRef = const SymExpr *;
-
//===----------------------------------------------------------------------===//
// High-level interface for handlers of path-sensitive diagnostics.
//===----------------------------------------------------------------------===//
@@ -125,6 +120,13 @@ public:
};
virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
+
+ bool shouldGenerateDiagnostics() const {
+ return getGenerationScheme() != None;
+ }
+
+ bool shouldAddPathEdges() const { return getGenerationScheme() == Extensive; }
+
virtual bool supportsLogicalOpControlFlow() const { return false; }
/// Return true if the PathDiagnosticConsumer supports individual
@@ -269,19 +271,21 @@ public:
static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
const SourceManager &SM);
- /// Create a location corresponding to the given valid ExplodedNode.
+ /// Create a location corresponding to the given valid ProgramPoint.
static PathDiagnosticLocation create(const ProgramPoint &P,
const SourceManager &SMng);
- /// Create a location corresponding to the next valid ExplodedNode as end
- /// of path location.
- static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N,
- const SourceManager &SM);
-
/// Convert the given location into a single kind location.
static PathDiagnosticLocation createSingleLocation(
const PathDiagnosticLocation &PDL);
+ /// Construct a source location that corresponds to either the beginning
+ /// or the end of the given statement, or a nearby valid source location
+ /// if the statement does not have a valid source location of its own.
+ static SourceLocation
+ getValidSourceLocation(const Stmt *S, LocationOrAnalysisDeclContext LAC,
+ bool UseEndOfStatement = false);
+
bool operator==(const PathDiagnosticLocation &X) const {
return K == X.K && Loc == X.Loc && Range == X.Range;
}
@@ -326,13 +330,6 @@ public:
void Profile(llvm::FoldingSetNodeID &ID) const;
void dump() const;
-
- /// Given an exploded node, retrieve the statement that should be used
- /// for the diagnostic location.
- static const Stmt *getStmt(const ExplodedNode *N);
-
- /// Retrieve the statement corresponding to the successor node.
- static const Stmt *getNextStmt(const ExplodedNode *N);
};
class PathDiagnosticLocationPair {
@@ -386,6 +383,7 @@ private:
StringRef Tag;
std::vector<SourceRange> ranges;
+ std::vector<FixItHint> fixits;
protected:
PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
@@ -430,9 +428,16 @@ public:
ranges.push_back(SourceRange(B,E));
}
+ void addFixit(FixItHint F) {
+ fixits.push_back(F);
+ }
+
/// Return the SourceRanges associated with this PathDiagnosticPiece.
ArrayRef<SourceRange> getRanges() const { return ranges; }
+ /// Return the fix-it hints associated with this PathDiagnosticPiece.
+ ArrayRef<FixItHint> getFixits() const { return fixits; }
+
virtual void Profile(llvm::FoldingSetNodeID &ID) const;
void setAsLastInMainSourceFile() {
@@ -446,7 +451,9 @@ public:
virtual void dump() const = 0;
};
-class PathPieces : public std::list<std::shared_ptr<PathDiagnosticPiece>> {
+using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>;
+
+class PathPieces : public std::list<PathDiagnosticPieceRef> {
void flattenTo(PathPieces &Primary, PathPieces &Current,
bool ShouldFlattenMacros) const;
@@ -486,65 +493,13 @@ public:
}
};
-/// Interface for classes constructing Stack hints.
-///
-/// If a PathDiagnosticEvent occurs in a different frame than the final
-/// diagnostic the hints can be used to summarize the effect of the call.
-class StackHintGenerator {
-public:
- virtual ~StackHintGenerator() = 0;
-
- /// Construct the Diagnostic message for the given ExplodedNode.
- virtual std::string getMessage(const ExplodedNode *N) = 0;
-};
-
-/// 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) {}
- ~StackHintGeneratorForSymbol() override = default;
-
- /// Search the call expression for the symbol Sym and dispatch the
- /// 'getMessageForX()' methods to construct a specific message.
- std::string getMessage(const ExplodedNode *N) override;
-
- /// 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 {
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.
- std::unique_ptr<StackHintGenerator> CallStackHint;
-
public:
PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
- StringRef s, bool addPosRange = true,
- StackHintGenerator *stackHint = nullptr)
- : PathDiagnosticSpotPiece(pos, s, Event, addPosRange),
- CallStackHint(stackHint) {}
+ StringRef s, bool addPosRange = true)
+ : PathDiagnosticSpotPiece(pos, s, Event, addPosRange) {}
~PathDiagnosticEventPiece() override;
/// Mark the diagnostic piece as being potentially prunable. This
@@ -561,16 +516,6 @@ public:
return IsPrunable.hasValue() ? IsPrunable.getValue() : false;
}
- bool hasCallStackHint() { return (bool)CallStackHint; }
-
- /// 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 {};
- }
-
void dump() const override;
static bool classof(const PathDiagnosticPiece *P) {
@@ -726,8 +671,6 @@ public:
PathPieces subPieces;
- bool containsEvent() const;
-
void flattenLocations() override {
PathDiagnosticSpotPiece::flattenLocations();
for (const auto &I : subPieces)
@@ -782,7 +725,7 @@ using FilesToLineNumsMap = std::map<FileID, std::set<unsigned>>;
/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces,
/// each which represent the pieces of the path.
class PathDiagnostic : public llvm::FoldingSetNode {
- std::string CheckName;
+ std::string CheckerName;
const Decl *DeclWithIssue;
std::string BugType;
std::string VerboseDesc;
@@ -806,7 +749,7 @@ class PathDiagnostic : public llvm::FoldingSetNode {
public:
PathDiagnostic() = delete;
- PathDiagnostic(StringRef CheckName, const Decl *DeclWithIssue,
+ PathDiagnostic(StringRef CheckerName, const Decl *DeclWithIssue,
StringRef bugtype, StringRef verboseDesc, StringRef shortDesc,
StringRef category, PathDiagnosticLocation LocationToUnique,
const Decl *DeclToUnique,
@@ -836,7 +779,7 @@ public:
bool isWithinCall() const { return !pathStack.empty(); }
- void setEndOfPath(std::shared_ptr<PathDiagnosticPiece> EndPiece) {
+ void setEndOfPath(PathDiagnosticPieceRef EndPiece) {
assert(!Loc.isValid() && "End location already set!");
Loc = EndPiece->getLocation();
assert(Loc.isValid() && "Invalid location for end-of-path piece");
@@ -849,26 +792,16 @@ public:
VerboseDesc += S;
}
- /// If the last piece of the report point to the header file, resets
- /// the location of the report to be the last location in the main source
- /// file.
- void resetDiagnosticLocationToMainFile();
-
StringRef getVerboseDescription() const { return VerboseDesc; }
StringRef getShortDescription() const {
return ShortDesc.empty() ? VerboseDesc : ShortDesc;
}
- StringRef getCheckName() const { return CheckName; }
+ StringRef getCheckerName() const { return CheckerName; }
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; }
-
using meta_iterator = std::deque<std::string>::const_iterator;
meta_iterator meta_begin() const { return OtherDesc.begin(); }
@@ -883,10 +816,23 @@ public:
return *ExecutedLines;
}
+ /// 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; }
+
+ void setDeclWithIssue(const Decl *D) {
+ DeclWithIssue = D;
+ }
+
PathDiagnosticLocation getLocation() const {
return Loc;
}
+ void setLocation(PathDiagnosticLocation NewLoc) {
+ Loc = NewLoc;
+ }
+
/// Get the location on which the report should be uniqued.
PathDiagnosticLocation getUniqueingLoc() const {
return UniqueingLoc;
@@ -917,7 +863,6 @@ public:
};
} // namespace ento
-
} // namespace clang
#endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_PATHDIAGNOSTIC_H
diff --git a/include/clang/Basic/AArch64SVEACLETypes.def b/include/clang/Basic/AArch64SVEACLETypes.def
new file mode 100644
index 000000000000..7d387587dc29
--- /dev/null
+++ b/include/clang/Basic/AArch64SVEACLETypes.def
@@ -0,0 +1,70 @@
+//===-- AArch64SVEACLETypes.def - Metadata about SVE types ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines various SVE builtin types. The macros are:
+//
+// SVE_TYPE(Name, Id, SingletonId) - A builtin type that has not been
+// covered by any other #define. Defining this macro covers all
+// the builtins.
+//
+// SVE_VECTOR_TYPE(Name, Id, SingletonId, ElKind, ElBits, IsSigned, IsFP) -
+// An SVE scalable vector.
+//
+// SVE_PREDICATE_TYPE(Name, Id, SingletonId, ElKind) - An SVE scalable
+// predicate.
+//
+// where:
+//
+// - Name is the name of the builtin type.
+//
+// - BuiltinType::Id is the enumerator defining the type.
+//
+// - Context.SingletonId is the global singleton of this type.
+//
+// - ElKind enumerates the type of the elements.
+//
+// - ElBits is the size of one element in bits.
+//
+// - IsSigned is true for vectors of signed integer elements and
+// for vectors of floating-point elements.
+//
+// - IsFP is true for vectors of floating-point elements.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SVE_VECTOR_TYPE
+#define SVE_VECTOR_TYPE(Name, Id, SingletonId, ElKind, ElBits, IsSigned, IsFP)\
+ SVE_TYPE(Name, Id, SingletonId)
+#endif
+
+#ifndef SVE_PREDICATE_TYPE
+#define SVE_PREDICATE_TYPE(Name, Id, SingletonId, ElKind)\
+ SVE_TYPE(Name, Id, SingletonId)
+#endif
+
+//===- Vector point types -----------------------------------------------===//
+
+SVE_VECTOR_TYPE("__SVInt8_t", SveInt8, SveInt8Ty, SveElSInt8, 8, true, false)
+SVE_VECTOR_TYPE("__SVInt16_t", SveInt16, SveInt16Ty, SveElSInt16, 16, true, false)
+SVE_VECTOR_TYPE("__SVInt32_t", SveInt32, SveInt32Ty, SveElSInt32, 32, true, false)
+SVE_VECTOR_TYPE("__SVInt64_t", SveInt64, SveInt64Ty, SveElSInt64, 64, true, false)
+
+SVE_VECTOR_TYPE("__SVUint8_t", SveUint8, SveUint8Ty, SveElUInt8, 8, false, false)
+SVE_VECTOR_TYPE("__SVUint16_t", SveUint16, SveUint16Ty, SveElUInt16, 16, false, false)
+SVE_VECTOR_TYPE("__SVUint32_t", SveUint32, SveUint32Ty, SveElUInt32, 32, false, false)
+SVE_VECTOR_TYPE("__SVUint64_t", SveUint64, SveUint64Ty, SveElUInt64, 64, false, false)
+
+SVE_VECTOR_TYPE("__SVFloat16_t", SveFloat16, SveFloat16Ty, SveElHalf, 16, true, true)
+SVE_VECTOR_TYPE("__SVFloat32_t", SveFloat32, SveFloat32Ty, SveElFloat, 32, true, true)
+SVE_VECTOR_TYPE("__SVFloat64_t", SveFloat64, SveFloat64Ty, SveElDouble, 64, true, true)
+
+SVE_PREDICATE_TYPE("__SVBool_t", SveBool, SveBoolTy, SveElBool)
+
+#undef SVE_VECTOR_TYPE
+#undef SVE_PREDICATE_TYPE
+#undef SVE_TYPE
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index d39b16e62b7f..c3a2ee325dfe 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -722,9 +722,25 @@ def AVRSignal : InheritableAttr, TargetSpecificAttr<TargetAVR> {
def AsmLabel : InheritableAttr {
let Spellings = [Keyword<"asm">, Keyword<"__asm__">];
- let Args = [StringArgument<"Label">];
+ let Args = [
+ // Label specifies the mangled name for the decl.
+ StringArgument<"Label">,
+
+ // IsLiteralLabel specifies whether the label is literal (i.e. suppresses
+ // the global C symbol prefix) or not. If not, the mangle-suppression prefix
+ // ('\01') is omitted from the decl name at the LLVM IR level.
+ //
+ // Non-literal labels are used by some external AST sources like LLDB.
+ BoolArgument<"IsLiteralLabel", /*optional=*/0, /*fake=*/1>
+ ];
let SemaHandler = 0;
- let Documentation = [Undocumented];
+ let Documentation = [AsmLabelDocs];
+ let AdditionalMembers =
+[{
+bool isEquivalent(AsmLabelAttr *Other) const {
+ return getLabel() == Other->getLabel() && getIsLiteralLabel() == Other->getIsLiteralLabel();
+}
+}];
}
def Availability : InheritableAttr {
@@ -911,6 +927,17 @@ def Const : InheritableAttr {
let Documentation = [Undocumented];
}
+def ConstInit : InheritableAttr {
+ // This attribute does not have a C [[]] spelling because it requires the
+ // CPlusPlus language option.
+ let Spellings = [Keyword<"constinit">,
+ Clang<"require_constant_initialization", 0>];
+ let Subjects = SubjectList<[GlobalVar], ErrorDiag>;
+ let Accessors = [Accessor<"isConstinit", [Keyword<"constinit">]>];
+ let Documentation = [ConstInitDocs];
+ let LangOpts = [CPlusPlus];
+}
+
def Constructor : InheritableAttr {
let Spellings = [GCC<"constructor">];
let Args = [DefaultIntArgument<"Priority", 65535>];
@@ -1170,7 +1197,7 @@ def ExtVectorType : Attr {
def FallThrough : StmtAttr {
let Spellings = [CXX11<"", "fallthrough", 201603>, C2x<"", "fallthrough">,
- CXX11<"clang", "fallthrough">];
+ CXX11<"clang", "fallthrough">, GCC<"fallthrough">];
// let Subjects = [NullStmt];
let Documentation = [FallthroughDocs];
}
@@ -1935,15 +1962,6 @@ def ReqdWorkGroupSize : InheritableAttr {
let Documentation = [Undocumented];
}
-def RequireConstantInit : InheritableAttr {
- // This attribute does not have a C [[]] spelling because it requires the
- // CPlusPlus language option.
- let Spellings = [Clang<"require_constant_initialization", 0>];
- let Subjects = SubjectList<[GlobalVar], ErrorDiag>;
- let Documentation = [RequireConstantInitDocs];
- let LangOpts = [CPlusPlus];
-}
-
def WorkGroupSizeHint : InheritableAttr {
// Does not have a [[]] spelling because it is an OpenCL-related attribute.
let Spellings = [GNU<"work_group_size_hint">];
@@ -2002,6 +2020,14 @@ def PragmaClangRodataSection : InheritableAttr {
let Documentation = [Undocumented];
}
+def PragmaClangRelroSection : InheritableAttr {
+ // This attribute has no spellings as it is only ever created implicitly.
+ let Spellings = [];
+ let Args = [StringArgument<"Name">];
+ let Subjects = SubjectList<[GlobalVar], ErrorDiag>;
+ let Documentation = [Undocumented];
+}
+
def PragmaClangTextSection : InheritableAttr {
// This attribute has no spellings as it is only ever created implicitly.
let Spellings = [];
@@ -2335,11 +2361,19 @@ def WarnUnused : InheritableAttr {
}
def WarnUnusedResult : InheritableAttr {
- let Spellings = [CXX11<"", "nodiscard", 201603>, C2x<"", "nodiscard">,
+ let Spellings = [CXX11<"", "nodiscard", 201907>, C2x<"", "nodiscard">,
CXX11<"clang", "warn_unused_result">,
GCC<"warn_unused_result">];
let Subjects = SubjectList<[ObjCMethod, Enum, Record, FunctionLike]>;
+ let Args = [StringArgument<"Message", 1>];
let Documentation = [WarnUnusedResultsDocs];
+ let AdditionalMembers = [{
+ // Check whether this the C++11 nodiscard version, even in non C++11
+ // spellings.
+ bool IsCXX11NoDiscard() const {
+ return this->getSemanticSpelling() == CXX11_nodiscard;
+ }
+ }];
}
def Weak : InheritableAttr {
@@ -2428,6 +2462,12 @@ def NoSanitizeSpecific : InheritableAttr {
let ASTNode = 0;
}
+def CFICanonicalJumpTable : InheritableAttr {
+ let Spellings = [Clang<"cfi_canonical_jump_table">];
+ let Subjects = SubjectList<[Function], ErrorDiag>;
+ let Documentation = [CFICanonicalJumpTableDocs];
+}
+
// C/C++ Thread safety attributes (e.g. for deadlock, data race checking)
// Not all of these attributes will be given a [[]] spelling. The attributes
// which require access to function parameter names cannot use the [[]] spelling
@@ -2788,6 +2828,20 @@ def TypeTagForDatatype : InheritableAttr {
let Documentation = [TypeTagForDatatypeDocs];
}
+def Owner : InheritableAttr {
+ let Spellings = [CXX11<"gsl", "Owner">];
+ let Subjects = SubjectList<[Struct]>;
+ let Args = [TypeArgument<"DerefType", /*opt=*/1>];
+ let Documentation = [LifetimeOwnerDocs];
+}
+
+def Pointer : InheritableAttr {
+ let Spellings = [CXX11<"gsl", "Pointer">];
+ let Subjects = SubjectList<[Struct]>;
+ let Args = [TypeArgument<"DerefType", /*opt=*/1>];
+ let Documentation = [LifetimePointerDocs];
+}
+
// Microsoft-related attributes
def MSNoVTable : InheritableAttr, TargetSpecificAttr<TargetMicrosoftCXXABI> {
@@ -2981,10 +3035,12 @@ def LoopHint : Attr {
let Args = [EnumArgument<"Option", "OptionType",
["vectorize", "vectorize_width", "interleave", "interleave_count",
"unroll", "unroll_count", "unroll_and_jam", "unroll_and_jam_count",
- "pipeline", "pipeline_initiation_interval", "distribute"],
+ "pipeline", "pipeline_initiation_interval", "distribute",
+ "vectorize_predicate"],
["Vectorize", "VectorizeWidth", "Interleave", "InterleaveCount",
"Unroll", "UnrollCount", "UnrollAndJam", "UnrollAndJamCount",
- "PipelineDisabled", "PipelineInitiationInterval", "Distribute"]>,
+ "PipelineDisabled", "PipelineInitiationInterval", "Distribute",
+ "VectorizePredicate"]>,
EnumArgument<"State", "LoopHintState",
["enable", "disable", "numeric", "assume_safety", "full"],
["Enable", "Disable", "Numeric", "AssumeSafety", "Full"]>,
@@ -3004,12 +3060,13 @@ def LoopHint : Attr {
case PipelineDisabled: return "pipeline";
case PipelineInitiationInterval: return "pipeline_initiation_interval";
case Distribute: return "distribute";
+ case VectorizePredicate: return "vectorize_predicate";
}
llvm_unreachable("Unhandled LoopHint option.");
}
void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const {
- unsigned SpellingIndex = getSpellingListIndex();
+ unsigned SpellingIndex = getAttributeSpellingListIndex();
// For "#pragma unroll" and "#pragma nounroll" the string "unroll" or
// "nounroll" is already emitted as the pragma name.
if (SpellingIndex == Pragma_nounroll || SpellingIndex == Pragma_nounroll_and_jam)
@@ -3045,7 +3102,7 @@ def LoopHint : Attr {
// Return a string suitable for identifying this attribute in diagnostics.
std::string getDiagnosticName(const PrintingPolicy &Policy) const {
- unsigned SpellingIndex = getSpellingListIndex();
+ unsigned SpellingIndex = getAttributeSpellingListIndex();
if (SpellingIndex == Pragma_nounroll)
return "#pragma nounroll";
else if (SpellingIndex == Pragma_unroll)
@@ -3176,11 +3233,16 @@ def OMPDeclareTargetDecl : InheritableAttr {
let Args = [
EnumArgument<"MapType", "MapTypeTy",
[ "to", "link" ],
- [ "MT_To", "MT_Link" ]>
+ [ "MT_To", "MT_Link" ]>,
+ EnumArgument<"DevType", "DevTypeTy",
+ [ "host", "nohost", "any" ],
+ [ "DT_Host", "DT_NoHost", "DT_Any" ]>
];
let AdditionalMembers = [{
void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const {
// Use fake syntax because it is for testing and debugging purpose only.
+ if (getDevType() != DT_Any)
+ OS << " device_type(" << ConvertDevTypeTyToStr(getDevType()) << ")";
if (getMapType() != MT_To)
OS << ' ' << ConvertMapTypeTyToStr(getMapType());
}
@@ -3193,6 +3255,14 @@ def OMPDeclareTargetDecl : InheritableAttr {
return llvm::None;
}
+ static llvm::Optional<DevTypeTy> getDeviceType(const ValueDecl *VD) {
+ if (!VD->hasAttrs())
+ return llvm::None;
+ if (const auto *Attr = VD->getAttr<OMPDeclareTargetDeclAttr>())
+ return Attr->getDevType();
+
+ return llvm::None;
+ }
}];
}
@@ -3219,6 +3289,82 @@ def OMPAllocateDecl : InheritableAttr {
let Documentation = [Undocumented];
}
+def OMPDeclareVariant : InheritableAttr {
+ let Spellings = [Pragma<"omp", "declare variant">];
+ let Subjects = SubjectList<[Function]>;
+ let SemaHandler = 0;
+ let HasCustomParsing = 1;
+ let InheritEvenIfAlreadyPresent = 1;
+ let Documentation = [OMPDeclareVariantDocs];
+ let Args = [
+ ExprArgument<"VariantFuncRef">,
+ ExprArgument<"Score">,
+ EnumArgument<"CtxSelectorSet", "CtxSelectorSetType",
+ [ "", "implementation"
+ ],
+ [
+ "CtxSetUnknown", "CtxSetImplementation"
+ ]>,
+ EnumArgument<"CtxScore", "ScoreType",
+ [ "", "score"
+ ],
+ [
+ "ScoreUnknown", "ScoreSpecified"
+ ]>,
+ EnumArgument<"CtxSelector", "CtxSelectorType",
+ [ "", "vendor"
+ ],
+ [
+ "CtxUnknown", "CtxVendor"
+ ]>,
+ VariadicStringArgument<"ImplVendors">
+ ];
+ let AdditionalMembers = [{
+ void printScore(raw_ostream & OS, const PrintingPolicy &Policy) const {
+ if (const Expr *E = getScore()) {
+ OS << "score(";
+ E->printPretty(OS, nullptr, Policy);
+ OS << "):";
+ }
+ }
+ void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy)
+ const {
+ assert(getCtxSelectorSet() != CtxSetUnknown &&
+ getCtxSelector() != CtxUnknown && "Unknown context selector.");
+ if (const Expr *E = getVariantFuncRef()) {
+ OS << "(";
+ E->printPretty(OS, nullptr, Policy);
+ OS << ")";
+ }
+ // TODO: add printing of real context selectors.
+ OS << " match(";
+ switch (getCtxSelectorSet()) {
+ case CtxSetImplementation:
+ OS << "implementation={";
+ switch (getCtxSelector()) {
+ case CtxVendor:
+ OS << "vendor(";
+ printScore(OS, Policy);
+ if (implVendors_size() > 0) {
+ OS << *implVendors(). begin();
+ for (StringRef VendorName : llvm::drop_begin(implVendors(), 1))
+ OS << ", " << VendorName;
+ }
+ OS << ")";
+ break;
+ case CtxUnknown:
+ llvm_unreachable("Unknown context selector.");
+ }
+ OS << "}";
+ break;
+ case CtxSetUnknown:
+ llvm_unreachable("Unknown context selector set.");
+ }
+ OS << ")";
+ }
+ }];
+}
+
def InternalLinkage : InheritableAttr {
let Spellings = [Clang<"internal_linkage">];
let Subjects = SubjectList<[Var, Function, CXXRecord]>;
diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td
index fac6116057dc..114a9856c5fb 100644
--- a/include/clang/Basic/AttrDocs.td
+++ b/include/clang/Basic/AttrDocs.td
@@ -1408,15 +1408,17 @@ all optional, but the attribute has to have at least one clause.
}];
}
-def RequireConstantInitDocs : Documentation {
+def ConstInitDocs : Documentation {
let Category = DocCatVariable;
+ let Heading = "require_constant_initialization, constinit (C++20)";
let Content = [{
This attribute specifies that the variable to which it is attached is intended
to have a `constant initializer <http://en.cppreference.com/w/cpp/language/constant_initialization>`_
according to the rules of [basic.start.static]. The variable is required to
have static or thread storage duration. If the initialization of the variable
is not a constant initializer an error will be produced. This attribute may
-only be used in C++.
+only be used in C++; the ``constinit`` spelling is only accepted in C++20
+onwards.
Note that in C++03 strict constant expression checking is not done. Instead
the attribute reports if Clang can emit the variable as a constant, even if it's
@@ -1431,6 +1433,12 @@ for constant initialization have been met. Since these requirements change
between dialects and have subtle pitfalls it's important to fail fast instead
of silently falling back on dynamic initialization.
+The first use of the attribute on a variable must be part of, or precede, the
+initializing declaration of the variable. C++20 requires the ``constinit``
+spelling of the attribute to be present on the initializing declaration if it
+is used anywhere. The other spellings can be specified on a forward declaration
+and omitted on a later initializing declaration.
+
.. code-block:: c++
// -std=c++14
@@ -1482,6 +1490,13 @@ generated when a function or its return type is marked with ``[[nodiscard]]``
potentially-evaluated discarded-value expression that is not explicitly cast to
`void`.
+A string literal may optionally be provided to the attribute, which will be
+reproduced in any resulting diagnostics. Redeclarations using different forms
+of the attribute (with or without the string literal or with different string
+literal contents) are allowed. If there are redeclarations of the entity with
+differing string literals, it is unspecified which one will be used by Clang
+in any resulting diagnostics.
+
.. code-block: c++
struct [[nodiscard]] error_info { /*...*/ };
error_info enable_missile_safety_mode();
@@ -1493,6 +1508,33 @@ potentially-evaluated discarded-value expression that is not explicitly cast to
}
error_info &foo();
void f() { foo(); } // Does not diagnose, error_info is a reference.
+
+Additionally, discarded temporaries resulting from a call to a constructor
+marked with ``[[nodiscard]]`` or a constructor of a type marked
+``[[nodiscard]]`` will also diagnose. This also applies to type conversions that
+use the annotated ``[[nodiscard]]`` constructor or result in an annotated type.
+
+.. code-block: c++
+ struct [[nodiscard]] marked_type {/*..*/ };
+ struct marked_ctor {
+ [[nodiscard]] marked_ctor();
+ marked_ctor(int);
+ };
+
+ struct S {
+ operator marked_type() const;
+ [[nodiscard]] operator int() const;
+ };
+
+ void usages() {
+ marked_type(); // diagnoses.
+ marked_ctor(); // diagnoses.
+ marked_ctor(3); // Does not diagnose, int constructor isn't marked nodiscard.
+
+ S s;
+ static_cast<marked_type>(s); // diagnoses
+ (int)s; // diagnoses
+ }
}];
}
@@ -2187,6 +2229,18 @@ to avoid false positives in other places.
}];
}
+def CFICanonicalJumpTableDocs : Documentation {
+ let Category = DocCatFunction;
+ let Heading = "cfi_canonical_jump_table";
+ let Content = [{
+.. _langext-cfi_canonical_jump_table:
+
+Use ``__attribute__((cfi_canonical_jump_table))`` on a function declaration to
+make the function's CFI jump table canonical. See :ref:`the CFI documentation
+<cfi-canonical-jump-tables>` for more details.
+ }];
+}
+
def DocCatTypeSafety : DocumentationCategory<"Type Safety Checking"> {
let Content = [{
Clang supports additional attributes to enable checking type safety properties
@@ -2504,6 +2558,30 @@ manipulating bits of the enumerator when issuing warnings.
}];
}
+def AsmLabelDocs : Documentation {
+ let Category = DocCatDecl;
+ let Content = [{
+This attribute can be used on a function or variable to specify its symbol name.
+
+On some targets, all C symbols are prefixed by default with a single character, typically ``_``. This was done historically to distinguish them from symbols used by other languages. (This prefix is also added to the standard Itanium C++ ABI prefix on "mangled" symbol names, so that e.g. on such targets the true symbol name for a C++ variable declared as ``int cppvar;`` would be ``__Z6cppvar``; note the two underscores.) This prefix is *not* added to the symbol names specified by the ``asm`` attribute; programmers wishing to match a C symbol name must compensate for this.
+
+For example, consider the following C code:
+
+.. code-block:: c
+
+ int var1 asm("altvar") = 1; // "altvar" in symbol table.
+ int var2 = 1; // "_var2" in symbol table.
+
+ void func1(void) asm("altfunc");
+ void func1(void) {} // "altfunc" in symbol table.
+ void func2(void) {} // "_func2" in symbol table.
+
+Clang's implementation of this attribute is compatible with GCC's, `documented here <https://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html>`_.
+
+While it is possible to use this attribute to name a special symbol used internally by the compiler, such as an LLVM intrinsic, this is neither recommended nor supported and may cause the compiler to crash or miscompile. Users who wish to gain access to intrinsic behavior are strongly encouraged to request new builtin functions.
+ }];
+}
+
def EnumExtensibilityDocs : Documentation {
let Category = DocCatDecl;
let Content = [{
@@ -2583,7 +2661,7 @@ is retained by the return value of the annotated function
It is only supported in C++.
This attribute provides an experimental implementation of the facility
-described in the C++ committee paper [http://wg21.link/p0936r0](P0936R0),
+described in the C++ committee paper `P0936R0 <http://wg21.link/p0936r0>`_,
and is subject to change as the design of the corresponding functionality
changes.
}];
@@ -2709,9 +2787,10 @@ def LoopHintDocs : Documentation {
let Content = [{
The ``#pragma clang loop`` directive allows loop optimization hints to be
specified for the subsequent loop. The directive allows pipelining to be
-disabled, or vectorization, interleaving, and unrolling to be enabled or disabled.
-Vector width, interleave count, unrolling count, and the initiation interval
-for pipelining can be explicitly specified. See `language extensions
+disabled, or vectorization, vector predication, interleaving, and unrolling to
+be enabled or disabled. Vector width, vector predication, interleave count,
+unrolling count, and the initiation interval for pipelining can be explicitly
+specified. See `language extensions
<http://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>`_
for details.
}];
@@ -3129,6 +3208,55 @@ The syntax of the declare target directive is as follows:
#pragma omp declare target new-line
declarations-definition-seq
#pragma omp end declare target new-line
+
+or
+
+ .. code-block:: c
+
+ #pragma omp declare target (extended-list) new-line
+
+or
+
+ .. code-block:: c
+
+ #pragma omp declare target clause[ [,] clause ... ] new-line
+
+where clause is one of the following:
+
+
+ .. code-block:: c
+
+ to(extended-list)
+ link(list)
+ device_type(host | nohost | any)
+ }];
+}
+
+def OMPDeclareVariantDocs : Documentation {
+ let Category = DocCatFunction;
+ let Heading = "#pragma omp declare variant";
+ let Content = [{
+The `declare variant` directive declares a specialized variant of a base
+ function and specifies the context in which that specialized variant is used.
+ The declare variant directive is a declarative directive.
+The syntax of the `declare variant` construct is as follows:
+
+ .. code-block:: none
+
+ #pragma omp declare variant(variant-func-id) clause new-line
+ [#pragma omp declare variant(variant-func-id) clause new-line]
+ [...]
+ function definition or declaration
+
+where clause is one of the following:
+
+ .. code-block:: none
+
+ match(context-selector-specification)
+
+and where `variant-func-id` is the name of a function variant that is either a
+ base language identifier or, for C++, a template-id.
+
}];
}
@@ -4194,4 +4322,72 @@ be accessed on both device side and host side. It has external linkage and is
not initialized on device side. It has internal linkage and is initialized by
the initializer on host side.
}];
-} \ No newline at end of file
+}
+
+def LifetimeOwnerDocs : Documentation {
+ let Category = DocCatDecl;
+ let Content = [{
+.. Note:: This attribute is experimental and its effect on analysis is subject to change in
+ a future version of clang.
+
+The attribute ``[[gsl::Owner(T)]]`` applies to structs and classes that own an
+object of type ``T``:
+
+.. code-block:: c++
+
+ class [[gsl::Owner(int)]] IntOwner {
+ private:
+ int value;
+ public:
+ int *getInt() { return &value; }
+ };
+
+The argument ``T`` is optional and is ignored.
+This attribute may be used by analysis tools and has no effect on code
+generation.
+
+See Pointer_ for an example.
+}];
+}
+
+def LifetimePointerDocs : Documentation {
+ let Category = DocCatDecl;
+ let Content = [{
+.. Note:: This attribute is experimental and its effect on analysis is subject to change in
+ a future version of clang.
+
+The attribute ``[[gsl::Pointer(T)]]`` applies to structs and classes that behave
+like pointers to an object of type ``T``:
+
+.. code-block:: c++
+
+ class [[gsl::Pointer(int)]] IntPointer {
+ private:
+ int *valuePointer;
+ public:
+ int *getInt() { return &valuePointer; }
+ };
+
+The argument ``T`` is optional and is ignored.
+This attribute may be used by analysis tools and has no effect on code
+generation.
+
+Example:
+When constructing an instance of a class annotated like this (a Pointer) from
+an instance of a class annotated with ``[[gsl::Owner]]`` (an Owner),
+then the analysis will consider the Pointer to point inside the Owner.
+When the Owner's lifetime ends, it will consider the Pointer to be dangling.
+
+.. code-block:: c++
+
+ int f() {
+ IntPointer P;
+ if (true) {
+ IntOwner O(7);
+ P = IntPointer(O); // P "points into" O
+ } // P is dangling
+ return P.get(); // error: Using a dangling Pointer.
+ }
+
+}];
+}
diff --git a/include/clang/Basic/AttributeCommonInfo.h b/include/clang/Basic/AttributeCommonInfo.h
new file mode 100644
index 000000000000..545e7e9a2b47
--- /dev/null
+++ b/include/clang/Basic/AttributeCommonInfo.h
@@ -0,0 +1,190 @@
+//======- AttributeCommonInfo.h - Base info about Attributes-----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the AttributeCommonInfo type, which is the base for a
+// ParsedAttr and is used by Attr as a way to share info between the two.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H
+#define LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+class IdentifierInfo;
+class ASTRecordWriter;
+
+class AttributeCommonInfo {
+public:
+ /// The style used to specify an attribute.
+ enum Syntax {
+ /// __attribute__((...))
+ AS_GNU,
+
+ /// [[...]]
+ AS_CXX11,
+
+ /// [[...]]
+ AS_C2x,
+
+ /// __declspec(...)
+ AS_Declspec,
+
+ /// [uuid("...")] class Foo
+ AS_Microsoft,
+
+ /// __ptr16, alignas(...), etc.
+ AS_Keyword,
+
+ /// #pragma ...
+ AS_Pragma,
+
+ // Note TableGen depends on the order above. Do not add or change the order
+ // without adding related code to TableGen/ClangAttrEmitter.cpp.
+ /// Context-sensitive version of a keyword attribute.
+ AS_ContextSensitiveKeyword,
+ };
+ enum Kind {
+#define PARSED_ATTR(NAME) AT_##NAME,
+#include "clang/Sema/AttrParsedAttrList.inc"
+#undef PARSED_ATTR
+ NoSemaHandlerAttribute,
+ IgnoredAttribute,
+ UnknownAttribute,
+ };
+
+private:
+ const IdentifierInfo *AttrName = nullptr;
+ const IdentifierInfo *ScopeName = nullptr;
+ SourceRange AttrRange;
+ const SourceLocation ScopeLoc;
+ // Corresponds to the Kind enum.
+ unsigned AttrKind : 16;
+ /// Corresponds to the Syntax enum.
+ unsigned SyntaxUsed : 3;
+ unsigned SpellingIndex : 4;
+
+protected:
+ static constexpr unsigned SpellingNotCalculated = 0xf;
+
+public:
+ AttributeCommonInfo(SourceRange AttrRange)
+ : AttrRange(AttrRange), ScopeLoc(), AttrKind(0), SyntaxUsed(0),
+ SpellingIndex(SpellingNotCalculated) {}
+
+ AttributeCommonInfo(SourceLocation AttrLoc)
+ : AttrRange(AttrLoc), ScopeLoc(), AttrKind(0), SyntaxUsed(0),
+ SpellingIndex(SpellingNotCalculated) {}
+
+ AttributeCommonInfo(const IdentifierInfo *AttrName,
+ const IdentifierInfo *ScopeName, SourceRange AttrRange,
+ SourceLocation ScopeLoc, Syntax SyntaxUsed)
+ : AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange),
+ ScopeLoc(ScopeLoc),
+ AttrKind(getParsedKind(AttrName, ScopeName, SyntaxUsed)),
+ SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingNotCalculated) {}
+
+ AttributeCommonInfo(const IdentifierInfo *AttrName,
+ const IdentifierInfo *ScopeName, SourceRange AttrRange,
+ SourceLocation ScopeLoc, Kind AttrKind, Syntax SyntaxUsed)
+ : AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange),
+ ScopeLoc(ScopeLoc), AttrKind(AttrKind), SyntaxUsed(SyntaxUsed),
+ SpellingIndex(SpellingNotCalculated) {}
+
+ AttributeCommonInfo(const IdentifierInfo *AttrName,
+ const IdentifierInfo *ScopeName, SourceRange AttrRange,
+ SourceLocation ScopeLoc, Kind AttrKind, Syntax SyntaxUsed,
+ unsigned Spelling)
+ : AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange),
+ ScopeLoc(ScopeLoc), AttrKind(AttrKind), SyntaxUsed(SyntaxUsed),
+ SpellingIndex(Spelling) {}
+
+ AttributeCommonInfo(const IdentifierInfo *AttrName, SourceRange AttrRange,
+ Syntax SyntaxUsed)
+ : AttrName(AttrName), ScopeName(nullptr), AttrRange(AttrRange),
+ ScopeLoc(), AttrKind(getParsedKind(AttrName, ScopeName, SyntaxUsed)),
+ SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingNotCalculated) {}
+
+ AttributeCommonInfo(SourceRange AttrRange, Kind K, Syntax SyntaxUsed)
+ : AttrName(nullptr), ScopeName(nullptr), AttrRange(AttrRange), ScopeLoc(),
+ AttrKind(K), SyntaxUsed(SyntaxUsed),
+ SpellingIndex(SpellingNotCalculated) {}
+
+ AttributeCommonInfo(SourceRange AttrRange, Kind K, Syntax SyntaxUsed,
+ unsigned Spelling)
+ : AttrName(nullptr), ScopeName(nullptr), AttrRange(AttrRange), ScopeLoc(),
+ AttrKind(K), SyntaxUsed(SyntaxUsed), SpellingIndex(Spelling) {}
+
+ AttributeCommonInfo(AttributeCommonInfo &&) = default;
+ AttributeCommonInfo(const AttributeCommonInfo &) = default;
+
+ Kind getParsedKind() const { return Kind(AttrKind); }
+ Syntax getSyntax() const { return Syntax(SyntaxUsed); }
+ const IdentifierInfo *getAttrName() const { return AttrName; }
+ SourceLocation getLoc() const { return AttrRange.getBegin(); }
+ SourceRange getRange() const { return AttrRange; }
+ void setRange(SourceRange R) { AttrRange = R; }
+
+ bool hasScope() const { return ScopeName; }
+ const IdentifierInfo *getScopeName() const { return ScopeName; }
+ SourceLocation getScopeLoc() const { return ScopeLoc; }
+
+ bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
+ bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; }
+
+ bool isGNUScope() const;
+
+ bool isAlignasAttribute() const {
+ // FIXME: Use a better mechanism to determine this.
+ return getParsedKind() == AT_Aligned && isKeywordAttribute();
+ }
+
+ bool isCXX11Attribute() const {
+ return SyntaxUsed == AS_CXX11 || isAlignasAttribute();
+ }
+
+ bool isC2xAttribute() const { return SyntaxUsed == AS_C2x; }
+
+ bool isKeywordAttribute() const {
+ return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword;
+ }
+
+ bool isContextSensitiveKeywordAttribute() const {
+ return SyntaxUsed == AS_ContextSensitiveKeyword;
+ }
+
+ unsigned getAttributeSpellingListIndex() const {
+ assert((isAttributeSpellingListCalculated() || AttrName) &&
+ "Spelling cannot be found");
+ return isAttributeSpellingListCalculated()
+ ? SpellingIndex
+ : calculateAttributeSpellingListIndex();
+ }
+ void setAttributeSpellingListIndex(unsigned V) { SpellingIndex = V; }
+
+ static Kind getParsedKind(const IdentifierInfo *Name,
+ const IdentifierInfo *Scope, Syntax SyntaxUsed);
+
+private:
+ /// Get an index into the attribute spelling list
+ /// defined in Attr.td. This index is used by an attribute
+ /// to pretty print itself.
+ unsigned calculateAttributeSpellingListIndex() const;
+
+ friend class clang::ASTRecordWriter;
+ // Used exclusively by ASTDeclWriter to get the raw spelling list state.
+ unsigned getAttributeSpellingListIndexRaw() const { return SpellingIndex; }
+
+protected:
+ bool isAttributeSpellingListCalculated() const {
+ return SpellingIndex != SpellingNotCalculated;
+ }
+};
+} // namespace clang
+
+#endif // LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index 984e607a2fc4..76e3b03de833 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -113,14 +113,17 @@ BUILTIN(__builtin_atan2l, "LdLdLd", "Fne")
BUILTIN(__builtin_abs , "ii" , "ncF")
BUILTIN(__builtin_copysign, "ddd", "ncF")
BUILTIN(__builtin_copysignf, "fff", "ncF")
+BUILTIN(__builtin_copysignf16, "hhh", "ncF")
BUILTIN(__builtin_copysignl, "LdLdLd", "ncF")
BUILTIN(__builtin_copysignf128, "LLdLLdLLd", "ncF")
BUILTIN(__builtin_fabs , "dd" , "ncF")
BUILTIN(__builtin_fabsf, "ff" , "ncF")
BUILTIN(__builtin_fabsl, "LdLd", "ncF")
+BUILTIN(__builtin_fabsf16, "hh" , "ncF")
BUILTIN(__builtin_fabsf128, "LLdLLd", "ncF")
BUILTIN(__builtin_fmod , "ddd" , "Fne")
BUILTIN(__builtin_fmodf, "fff" , "Fne")
+BUILTIN(__builtin_fmodf16, "hhh" , "Fne")
BUILTIN(__builtin_fmodl, "LdLdLd", "Fne")
BUILTIN(__builtin_frexp , "ddi*" , "Fn")
BUILTIN(__builtin_frexpf, "ffi*" , "Fn")
@@ -154,6 +157,7 @@ BUILTIN(__builtin_powif, "ffi" , "Fnc")
BUILTIN(__builtin_powil, "LdLdi", "Fnc")
BUILTIN(__builtin_pow , "ddd" , "Fne")
BUILTIN(__builtin_powf, "fff" , "Fne")
+BUILTIN(__builtin_powf16, "hhh" , "Fne")
BUILTIN(__builtin_powl, "LdLdLd", "Fne")
// Standard unary libc/libm functions with double/float/long double variants:
@@ -180,9 +184,11 @@ BUILTIN(__builtin_cbrtf, "ff", "Fnc")
BUILTIN(__builtin_cbrtl, "LdLd", "Fnc")
BUILTIN(__builtin_ceil , "dd" , "Fnc")
BUILTIN(__builtin_ceilf, "ff" , "Fnc")
+BUILTIN(__builtin_ceilf16, "hh" , "Fnc")
BUILTIN(__builtin_ceill, "LdLd", "Fnc")
BUILTIN(__builtin_cos , "dd" , "Fne")
BUILTIN(__builtin_cosf, "ff" , "Fne")
+BUILTIN(__builtin_cosf16, "hh" , "Fne")
BUILTIN(__builtin_cosh , "dd" , "Fne")
BUILTIN(__builtin_coshf, "ff" , "Fne")
BUILTIN(__builtin_coshl, "LdLd", "Fne")
@@ -195,9 +201,11 @@ BUILTIN(__builtin_erfcf, "ff", "Fne")
BUILTIN(__builtin_erfcl, "LdLd", "Fne")
BUILTIN(__builtin_exp , "dd" , "Fne")
BUILTIN(__builtin_expf, "ff" , "Fne")
+BUILTIN(__builtin_expf16, "hh" , "Fne")
BUILTIN(__builtin_expl, "LdLd", "Fne")
BUILTIN(__builtin_exp2 , "dd" , "Fne")
BUILTIN(__builtin_exp2f, "ff" , "Fne")
+BUILTIN(__builtin_exp2f16, "hh" , "Fne")
BUILTIN(__builtin_exp2l, "LdLd", "Fne")
BUILTIN(__builtin_expm1 , "dd", "Fne")
BUILTIN(__builtin_expm1f, "ff", "Fne")
@@ -207,15 +215,19 @@ BUILTIN(__builtin_fdimf, "fff", "Fne")
BUILTIN(__builtin_fdiml, "LdLdLd", "Fne")
BUILTIN(__builtin_floor , "dd" , "Fnc")
BUILTIN(__builtin_floorf, "ff" , "Fnc")
+BUILTIN(__builtin_floorf16, "hh" , "Fnc")
BUILTIN(__builtin_floorl, "LdLd", "Fnc")
BUILTIN(__builtin_fma, "dddd", "Fne")
BUILTIN(__builtin_fmaf, "ffff", "Fne")
+BUILTIN(__builtin_fmaf16, "hhhh", "Fne")
BUILTIN(__builtin_fmal, "LdLdLdLd", "Fne")
BUILTIN(__builtin_fmax, "ddd", "Fnc")
BUILTIN(__builtin_fmaxf, "fff", "Fnc")
+BUILTIN(__builtin_fmaxf16, "hhh", "Fnc")
BUILTIN(__builtin_fmaxl, "LdLdLd", "Fnc")
BUILTIN(__builtin_fmin, "ddd", "Fnc")
BUILTIN(__builtin_fminf, "fff", "Fnc")
+BUILTIN(__builtin_fminf16, "hhh", "Fnc")
BUILTIN(__builtin_fminl, "LdLdLd", "Fnc")
BUILTIN(__builtin_hypot , "ddd" , "Fne")
BUILTIN(__builtin_hypotf, "fff" , "Fne")
@@ -235,17 +247,20 @@ BUILTIN(__builtin_llroundl, "LLiLd", "Fne")
BUILTIN(__builtin_log , "dd" , "Fne")
BUILTIN(__builtin_log10 , "dd" , "Fne")
BUILTIN(__builtin_log10f, "ff" , "Fne")
+BUILTIN(__builtin_log10f16, "hh" , "Fne")
BUILTIN(__builtin_log10l, "LdLd", "Fne")
BUILTIN(__builtin_log1p , "dd" , "Fne")
BUILTIN(__builtin_log1pf, "ff" , "Fne")
BUILTIN(__builtin_log1pl, "LdLd", "Fne")
BUILTIN(__builtin_log2, "dd" , "Fne")
BUILTIN(__builtin_log2f, "ff" , "Fne")
+BUILTIN(__builtin_log2f16, "hh" , "Fne")
BUILTIN(__builtin_log2l, "LdLd" , "Fne")
BUILTIN(__builtin_logb , "dd", "Fne")
BUILTIN(__builtin_logbf, "ff", "Fne")
BUILTIN(__builtin_logbl, "LdLd", "Fne")
BUILTIN(__builtin_logf, "ff" , "Fne")
+BUILTIN(__builtin_logf16, "hh" , "Fne")
BUILTIN(__builtin_logl, "LdLd", "Fne")
BUILTIN(__builtin_lrint , "Lid", "Fne")
BUILTIN(__builtin_lrintf, "Lif", "Fne")
@@ -270,9 +285,11 @@ BUILTIN(__builtin_remquof, "fffi*", "Fn")
BUILTIN(__builtin_remquol, "LdLdLdi*", "Fn")
BUILTIN(__builtin_rint , "dd", "Fnc")
BUILTIN(__builtin_rintf, "ff", "Fnc")
+BUILTIN(__builtin_rintf16, "hh", "Fnc")
BUILTIN(__builtin_rintl, "LdLd", "Fnc")
BUILTIN(__builtin_round, "dd" , "Fnc")
BUILTIN(__builtin_roundf, "ff" , "Fnc")
+BUILTIN(__builtin_roundf16, "hh" , "Fnc")
BUILTIN(__builtin_roundl, "LdLd" , "Fnc")
BUILTIN(__builtin_scalbln , "ddLi", "Fne")
BUILTIN(__builtin_scalblnf, "ffLi", "Fne")
@@ -282,12 +299,14 @@ BUILTIN(__builtin_scalbnf, "ffi", "Fne")
BUILTIN(__builtin_scalbnl, "LdLdi", "Fne")
BUILTIN(__builtin_sin , "dd" , "Fne")
BUILTIN(__builtin_sinf, "ff" , "Fne")
+BUILTIN(__builtin_sinf16, "hh" , "Fne")
BUILTIN(__builtin_sinh , "dd" , "Fne")
BUILTIN(__builtin_sinhf, "ff" , "Fne")
BUILTIN(__builtin_sinhl, "LdLd", "Fne")
BUILTIN(__builtin_sinl, "LdLd", "Fne")
BUILTIN(__builtin_sqrt , "dd" , "Fne")
BUILTIN(__builtin_sqrtf, "ff" , "Fne")
+BUILTIN(__builtin_sqrtf16, "hh" , "Fne")
BUILTIN(__builtin_sqrtl, "LdLd", "Fne")
BUILTIN(__builtin_tan , "dd" , "Fne")
BUILTIN(__builtin_tanf, "ff" , "Fne")
@@ -301,6 +320,7 @@ BUILTIN(__builtin_tgammal, "LdLd", "Fne")
BUILTIN(__builtin_trunc , "dd", "Fnc")
BUILTIN(__builtin_truncf, "ff", "Fnc")
BUILTIN(__builtin_truncl, "LdLd", "Fnc")
+BUILTIN(__builtin_truncf16, "hh", "Fnc")
// C99 complex builtins
BUILTIN(__builtin_cabs, "dXd", "Fne")
@@ -394,6 +414,7 @@ BUILTIN(__builtin_signbitl, "iLd", "Fnc")
// Special FP builtins.
BUILTIN(__builtin_canonicalize, "dd", "nc")
BUILTIN(__builtin_canonicalizef, "ff", "nc")
+BUILTIN(__builtin_canonicalizef16, "hh", "nc")
BUILTIN(__builtin_canonicalizel, "LdLd", "nc")
// Builtins for arithmetic.
@@ -440,7 +461,7 @@ BUILTIN(__builtin_rotateleft64, "UWiUWiUWi", "nc")
BUILTIN(__builtin_rotateright8, "UcUcUc", "nc")
BUILTIN(__builtin_rotateright16, "UsUsUs", "nc")
BUILTIN(__builtin_rotateright32, "UZiUZiUZi", "nc")
-BUILTIN(__builtin_rotateright64, "UWiUWiWi", "nc")
+BUILTIN(__builtin_rotateright64, "UWiUWiUWi", "nc")
// Random GCC builtins
BUILTIN(__builtin_constant_p, "i.", "nctu")
@@ -984,9 +1005,7 @@ LIBBUILTIN(pthread_create, "", "fC<2,3>", "pthread.h", ALL_GNU_LANGUAGES)
LIBBUILTIN(_setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(__sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_LANGUAGES)
-LIBBUILTIN(setjmp_syscall, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(savectx, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
-LIBBUILTIN(qsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(getcontext, "iK*", "fj", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h", ALL_GNU_LANGUAGES)
@@ -1449,7 +1468,7 @@ BUILTIN(__builtin_operator_new, "v*z", "tc")
BUILTIN(__builtin_operator_delete, "vv*", "tn")
BUILTIN(__builtin_char_memchr, "c*cC*iz", "n")
BUILTIN(__builtin_dump_struct, "ivC*v*", "tn")
-BUILTIN(__builtin_preserve_access_index, "vC*vC*", "nU")
+BUILTIN(__builtin_preserve_access_index, "v.", "t")
// Safestack builtins
BUILTIN(__builtin___get_unsafe_stack_start, "v*", "Fn")
diff --git a/include/clang/Basic/BuiltinsAArch64.def b/include/clang/Basic/BuiltinsAArch64.def
index 7701ad98f483..4df8d5a16762 100644
--- a/include/clang/Basic/BuiltinsAArch64.def
+++ b/include/clang/Basic/BuiltinsAArch64.def
@@ -91,12 +91,18 @@ LANGBUILTIN(__sevl, "v", "", ALL_MS_LANGUAGES)
// Misc
BUILTIN(__builtin_sponentry, "v*", "c")
+// Transactional Memory Extension
+BUILTIN(__builtin_arm_tstart, "WUi", "nj")
+BUILTIN(__builtin_arm_tcommit, "v", "n")
+BUILTIN(__builtin_arm_tcancel, "vWUIi", "n")
+BUILTIN(__builtin_arm_ttest, "WUi", "nc")
+
TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedAdd, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedAdd, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAnd64, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement64, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange64, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -106,9 +112,9 @@ TARGET_HEADER_BUILTIN(_InterlockedIncrement64, "LLiLLiD*", "nh", "intrin.h"
TARGET_HEADER_BUILTIN(_InterlockedOr64, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedXor64, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd_acq, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd_rel, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd_nf, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd_acq, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd_rel, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd_nf, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd8_acq, "ccD*c", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd8_rel, "ccD*c", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd8_nf, "ccD*c", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -125,9 +131,9 @@ TARGET_HEADER_BUILTIN(_InterlockedExchange8_rel, "ccD*c", "nh", "intrin.h
TARGET_HEADER_BUILTIN(_InterlockedExchange16_acq, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange16_nf, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange16_rel, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedExchange_acq, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedExchange_nf, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedExchange_rel, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchange_acq, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchange_nf, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchange_rel, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange64_acq, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange64_nf, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange64_rel, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -138,9 +144,9 @@ TARGET_HEADER_BUILTIN(_InterlockedCompareExchange8_rel, "ccD*cc", "nh",
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange16_acq, "ssD*ss", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange16_nf, "ssD*ss", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange16_rel, "ssD*ss", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_acq, "LiLiD*LiLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_nf, "LiLiD*LiLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_rel, "LiLiD*LiLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_acq, "NiNiD*NiNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_nf, "NiNiD*NiNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_rel, "NiNiD*NiNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_acq, "LLiLLiD*LLiLLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_nf, "LLiLLiD*LLiLLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_rel, "LLiLLiD*LLiLLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -151,9 +157,9 @@ TARGET_HEADER_BUILTIN(_InterlockedOr8_rel, "ccD*c", "nh", "intrin.h", ALL
TARGET_HEADER_BUILTIN(_InterlockedOr16_acq, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedOr16_nf, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedOr16_rel, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedOr_acq, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedOr_nf, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedOr_rel, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedOr_acq, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedOr_nf, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedOr_rel, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedOr64_acq, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedOr64_nf, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedOr64_rel, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -164,9 +170,9 @@ TARGET_HEADER_BUILTIN(_InterlockedXor8_rel, "ccD*c", "nh", "intrin.h", AL
TARGET_HEADER_BUILTIN(_InterlockedXor16_acq, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedXor16_nf, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedXor16_rel, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedXor_acq, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedXor_nf, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedXor_rel, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedXor_acq, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedXor_nf, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedXor_rel, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedXor64_acq, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedXor64_nf, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedXor64_rel, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -177,9 +183,9 @@ TARGET_HEADER_BUILTIN(_InterlockedAnd8_rel, "ccD*c", "nh", "intrin.h", AL
TARGET_HEADER_BUILTIN(_InterlockedAnd16_acq, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAnd16_nf, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAnd16_rel, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedAnd_acq, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedAnd_nf, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedAnd_rel, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedAnd_acq, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedAnd_nf, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedAnd_rel, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAnd64_acq, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAnd64_nf, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAnd64_rel, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -187,9 +193,9 @@ TARGET_HEADER_BUILTIN(_InterlockedAnd64_rel, "LLiLLiD*LLi", "nh", "intrin.h", AL
TARGET_HEADER_BUILTIN(_InterlockedIncrement16_acq, "ssD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedIncrement16_nf, "ssD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedIncrement16_rel, "ssD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedIncrement_acq, "LiLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedIncrement_nf, "LiLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedIncrement_rel, "LiLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedIncrement_acq, "NiNiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedIncrement_nf, "NiNiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedIncrement_rel, "NiNiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedIncrement64_acq, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedIncrement64_nf, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedIncrement64_rel, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -197,9 +203,9 @@ TARGET_HEADER_BUILTIN(_InterlockedIncrement64_rel, "LLiLLiD*", "nh", "intrin.h",
TARGET_HEADER_BUILTIN(_InterlockedDecrement16_acq, "ssD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement16_nf, "ssD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement16_rel, "ssD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedDecrement_acq, "LiLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedDecrement_nf, "LiLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedDecrement_rel, "LiLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedDecrement_acq, "NiNiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedDecrement_nf, "NiNiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedDecrement_rel, "NiNiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement64_acq, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement64_nf, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement64_rel, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
diff --git a/include/clang/Basic/BuiltinsAMDGPU.def b/include/clang/Basic/BuiltinsAMDGPU.def
index 2f8fb9000a76..9b3a0f96798f 100644
--- a/include/clang/Basic/BuiltinsAMDGPU.def
+++ b/include/clang/Basic/BuiltinsAMDGPU.def
@@ -118,6 +118,13 @@ BUILTIN(__builtin_amdgcn_cvt_pknorm_u16, "E2Usff", "nc")
BUILTIN(__builtin_amdgcn_cvt_pk_i16, "E2sii", "nc")
BUILTIN(__builtin_amdgcn_cvt_pk_u16, "E2UsUiUi", "nc")
BUILTIN(__builtin_amdgcn_cvt_pk_u8_f32, "UifUiUi", "nc")
+BUILTIN(__builtin_amdgcn_sad_u8, "UiUiUiUi", "nc")
+BUILTIN(__builtin_amdgcn_msad_u8, "UiUiUiUi", "nc")
+BUILTIN(__builtin_amdgcn_sad_hi_u8, "UiUiUiUi", "nc")
+BUILTIN(__builtin_amdgcn_sad_u16, "UiUiUiUi", "nc")
+BUILTIN(__builtin_amdgcn_qsad_pk_u16_u8, "LUiLUiUiLUi", "nc")
+BUILTIN(__builtin_amdgcn_mqsad_pk_u16_u8, "LUiLUiUiLUi", "nc")
+BUILTIN(__builtin_amdgcn_mqsad_u32_u8, "V4UiLUiUiV4Ui", "nc")
//===----------------------------------------------------------------------===//
// CI+ only builtins.
@@ -125,6 +132,8 @@ BUILTIN(__builtin_amdgcn_cvt_pk_u8_f32, "UifUiUi", "nc")
TARGET_BUILTIN(__builtin_amdgcn_s_dcache_inv_vol, "v", "n", "ci-insts")
TARGET_BUILTIN(__builtin_amdgcn_buffer_wbinvl1_vol, "v", "n", "ci-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_gws_sema_release_all, "vUi", "n", "ci-insts")
+TARGET_BUILTIN(__builtin_amdgcn_is_shared, "bvC*0", "nc", "flat-address-space")
+TARGET_BUILTIN(__builtin_amdgcn_is_private, "bvC*0", "nc", "flat-address-space")
//===----------------------------------------------------------------------===//
// Interpolation builtins.
diff --git a/include/clang/Basic/BuiltinsARM.def b/include/clang/Basic/BuiltinsARM.def
index 3f0765115b1c..19b51694aa22 100644
--- a/include/clang/Basic/BuiltinsARM.def
+++ b/include/clang/Basic/BuiltinsARM.def
@@ -221,9 +221,9 @@ TARGET_HEADER_BUILTIN(_InterlockedIncrement64, "LLiLLiD*", "nh", "intrin.h"
TARGET_HEADER_BUILTIN(_InterlockedOr64, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedXor64, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd_acq, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd_rel, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd_nf, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd_acq, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd_rel, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd_nf, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd8_acq, "ccD*c", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd8_rel, "ccD*c", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchangeAdd8_nf, "ccD*c", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -240,9 +240,9 @@ TARGET_HEADER_BUILTIN(_InterlockedExchange8_rel, "ccD*c", "nh", "intrin.h
TARGET_HEADER_BUILTIN(_InterlockedExchange16_acq, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange16_nf, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange16_rel, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedExchange_acq, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedExchange_nf, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedExchange_rel, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchange_acq, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchange_nf, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedExchange_rel, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange64_acq, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange64_nf, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange64_rel, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -253,9 +253,9 @@ TARGET_HEADER_BUILTIN(_InterlockedCompareExchange8_rel, "ccD*cc", "nh",
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange16_acq, "ssD*ss", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange16_nf, "ssD*ss", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange16_rel, "ssD*ss", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_acq, "LiLiD*LiLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_nf, "LiLiD*LiLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_rel, "LiLiD*LiLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_acq, "NiNiD*NiNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_nf, "NiNiD*NiNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_rel, "NiNiD*NiNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_acq, "LLiLLiD*LLiLLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_nf, "LLiLLiD*LLiLLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_rel, "LLiLLiD*LLiLLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -266,9 +266,9 @@ TARGET_HEADER_BUILTIN(_InterlockedOr8_rel, "ccD*c", "nh", "intrin.h", ALL
TARGET_HEADER_BUILTIN(_InterlockedOr16_acq, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedOr16_nf, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedOr16_rel, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedOr_acq, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedOr_nf, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedOr_rel, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedOr_acq, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedOr_nf, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedOr_rel, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedOr64_acq, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedOr64_nf, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedOr64_rel, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -279,9 +279,9 @@ TARGET_HEADER_BUILTIN(_InterlockedXor8_rel, "ccD*c", "nh", "intrin.h", AL
TARGET_HEADER_BUILTIN(_InterlockedXor16_acq, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedXor16_nf, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedXor16_rel, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedXor_acq, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedXor_nf, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedXor_rel, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedXor_acq, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedXor_nf, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedXor_rel, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedXor64_acq, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedXor64_nf, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedXor64_rel, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -292,9 +292,9 @@ TARGET_HEADER_BUILTIN(_InterlockedAnd8_rel, "ccD*c", "nh", "intrin.h", AL
TARGET_HEADER_BUILTIN(_InterlockedAnd16_acq, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAnd16_nf, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAnd16_rel, "ssD*s", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedAnd_acq, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedAnd_nf, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedAnd_rel, "LiLiD*Li", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedAnd_acq, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedAnd_nf, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedAnd_rel, "NiNiD*Ni", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAnd64_acq, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAnd64_nf, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAnd64_rel, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -302,9 +302,9 @@ TARGET_HEADER_BUILTIN(_InterlockedAnd64_rel, "LLiLLiD*LLi", "nh", "intrin.h", AL
TARGET_HEADER_BUILTIN(_InterlockedIncrement16_acq, "ssD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedIncrement16_nf, "ssD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedIncrement16_rel, "ssD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedIncrement_acq, "LiLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedIncrement_nf, "LiLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedIncrement_rel, "LiLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedIncrement_acq, "NiNiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedIncrement_nf, "NiNiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedIncrement_rel, "NiNiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedIncrement64_acq, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedIncrement64_nf, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedIncrement64_rel, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
@@ -312,9 +312,9 @@ TARGET_HEADER_BUILTIN(_InterlockedIncrement64_rel, "LLiLLiD*", "nh", "intrin.h",
TARGET_HEADER_BUILTIN(_InterlockedDecrement16_acq, "ssD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement16_nf, "ssD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement16_rel, "ssD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedDecrement_acq, "LiLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedDecrement_nf, "LiLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
-TARGET_HEADER_BUILTIN(_InterlockedDecrement_rel, "LiLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedDecrement_acq, "NiNiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedDecrement_nf, "NiNiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(_InterlockedDecrement_rel, "NiNiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement64_acq, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement64_nf, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement64_rel, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
diff --git a/include/clang/Basic/BuiltinsBPF.def b/include/clang/Basic/BuiltinsBPF.def
new file mode 100644
index 000000000000..bd96b9ef531b
--- /dev/null
+++ b/include/clang/Basic/BuiltinsBPF.def
@@ -0,0 +1,24 @@
+//===--- BuiltinsBPF.def - BPF Builtin function database --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the BPF-specific builtin function database. Users of
+// this file must define the BUILTIN macro to make use of this information.
+//
+//===----------------------------------------------------------------------===//
+
+// The format of this database matches clang/Basic/Builtins.def.
+
+#if defined(BUILTIN) && !defined(TARGET_BUILTIN)
+# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS)
+#endif
+
+// Get record field information.
+TARGET_BUILTIN(__builtin_preserve_field_info, "Ui.", "t", "")
+
+#undef BUILTIN
+#undef TARGET_BUILTIN
diff --git a/include/clang/Basic/BuiltinsPPC.def b/include/clang/Basic/BuiltinsPPC.def
index 3b6348ad7d70..314e1cc05907 100644
--- a/include/clang/Basic/BuiltinsPPC.def
+++ b/include/clang/Basic/BuiltinsPPC.def
@@ -50,17 +50,17 @@ BUILTIN(__builtin_altivec_vavguw, "V4UiV4UiV4Ui", "")
BUILTIN(__builtin_altivec_vrfip, "V4fV4f", "")
-BUILTIN(__builtin_altivec_vcfsx, "V4fV4iIi", "")
-BUILTIN(__builtin_altivec_vcfux, "V4fV4iIi", "")
+BUILTIN(__builtin_altivec_vcfsx, "V4fV4SiIi", "")
+BUILTIN(__builtin_altivec_vcfux, "V4fV4UiIi", "")
BUILTIN(__builtin_altivec_vctsxs, "V4SiV4fIi", "")
BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fIi", "")
-BUILTIN(__builtin_altivec_dss, "vUi", "")
+BUILTIN(__builtin_altivec_dss, "vUIi", "")
BUILTIN(__builtin_altivec_dssall, "v", "")
-BUILTIN(__builtin_altivec_dst, "vvC*iUi", "")
-BUILTIN(__builtin_altivec_dstt, "vvC*iUi", "")
-BUILTIN(__builtin_altivec_dstst, "vvC*iUi", "")
-BUILTIN(__builtin_altivec_dststt, "vvC*iUi", "")
+BUILTIN(__builtin_altivec_dst, "vvC*iUIi", "")
+BUILTIN(__builtin_altivec_dstt, "vvC*iUIi", "")
+BUILTIN(__builtin_altivec_dstst, "vvC*iUIi", "")
+BUILTIN(__builtin_altivec_dststt, "vvC*iUIi", "")
BUILTIN(__builtin_altivec_vexptefp, "V4fV4f", "")
diff --git a/include/clang/Basic/BuiltinsWebAssembly.def b/include/clang/Basic/BuiltinsWebAssembly.def
index 63177f016ac7..7fed9d2e43e7 100644
--- a/include/clang/Basic/BuiltinsWebAssembly.def
+++ b/include/clang/Basic/BuiltinsWebAssembly.def
@@ -31,6 +31,8 @@ TARGET_BUILTIN(__builtin_wasm_data_drop, "vIUi", "", "bulk-memory")
// Thread-local storage
TARGET_BUILTIN(__builtin_wasm_tls_size, "z", "nc", "bulk-memory")
+TARGET_BUILTIN(__builtin_wasm_tls_align, "z", "nc", "bulk-memory")
+TARGET_BUILTIN(__builtin_wasm_tls_base, "v*", "nU", "bulk-memory")
// Floating point min/max
BUILTIN(__builtin_wasm_min_f32, "fff", "nc")
@@ -47,6 +49,16 @@ BUILTIN(__builtin_wasm_atomic_wait_i32, "ii*iLLi", "n")
BUILTIN(__builtin_wasm_atomic_wait_i64, "iLLi*LLiLLi", "n")
BUILTIN(__builtin_wasm_atomic_notify, "Uii*Ui", "n")
+// Trapping fp-to-int conversions
+BUILTIN(__builtin_wasm_trunc_s_i32_f32, "if", "nc")
+BUILTIN(__builtin_wasm_trunc_u_i32_f32, "if", "nc")
+BUILTIN(__builtin_wasm_trunc_s_i32_f64, "id", "nc")
+BUILTIN(__builtin_wasm_trunc_u_i32_f64, "id", "nc")
+BUILTIN(__builtin_wasm_trunc_s_i64_f32, "LLif", "nc")
+BUILTIN(__builtin_wasm_trunc_u_i64_f32, "LLif", "nc")
+BUILTIN(__builtin_wasm_trunc_s_i64_f64, "LLid", "nc")
+BUILTIN(__builtin_wasm_trunc_u_i64_f64, "LLid", "nc")
+
// Saturating fp-to-int conversions
TARGET_BUILTIN(__builtin_wasm_trunc_saturate_s_i32_f32, "if", "nc", "nontrapping-fptoint")
TARGET_BUILTIN(__builtin_wasm_trunc_saturate_u_i32_f32, "if", "nc", "nontrapping-fptoint")
@@ -58,6 +70,8 @@ TARGET_BUILTIN(__builtin_wasm_trunc_saturate_s_i64_f64, "LLid", "nc", "nontrappi
TARGET_BUILTIN(__builtin_wasm_trunc_saturate_u_i64_f64, "LLid", "nc", "nontrapping-fptoint")
// SIMD builtins
+TARGET_BUILTIN(__builtin_wasm_swizzle_v8x16, "V16cV16cV16c", "nc", "unimplemented-simd128")
+
TARGET_BUILTIN(__builtin_wasm_extract_lane_s_i8x16, "iV16cIi", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_extract_lane_u_i8x16, "iV16cIi", "nc", "unimplemented-simd128")
TARGET_BUILTIN(__builtin_wasm_extract_lane_s_i16x8, "iV8sIi", "nc", "simd128")
@@ -106,10 +120,29 @@ TARGET_BUILTIN(__builtin_wasm_max_f64x2, "V2dV2dV2d", "nc", "unimplemented-simd1
TARGET_BUILTIN(__builtin_wasm_sqrt_f32x4, "V4fV4f", "nc", "unimplemented-simd128")
TARGET_BUILTIN(__builtin_wasm_sqrt_f64x2, "V2dV2d", "nc", "unimplemented-simd128")
+TARGET_BUILTIN(__builtin_wasm_qfma_f32x4, "V4fV4fV4fV4f", "nc", "simd128")
+TARGET_BUILTIN(__builtin_wasm_qfms_f32x4, "V4fV4fV4fV4f", "nc", "simd128")
+TARGET_BUILTIN(__builtin_wasm_qfma_f64x2, "V2dV2dV2dV2d", "nc", "unimplemented-simd128")
+TARGET_BUILTIN(__builtin_wasm_qfms_f64x2, "V2dV2dV2dV2d", "nc", "unimplemented-simd128")
+
TARGET_BUILTIN(__builtin_wasm_trunc_saturate_s_i32x4_f32x4, "V4iV4f", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_trunc_saturate_u_i32x4_f32x4, "V4iV4f", "nc", "simd128")
TARGET_BUILTIN(__builtin_wasm_trunc_saturate_s_i64x2_f64x2, "V2LLiV2d", "nc", "unimplemented-simd128")
TARGET_BUILTIN(__builtin_wasm_trunc_saturate_u_i64x2_f64x2, "V2LLiV2d", "nc", "unimplemented-simd128")
+TARGET_BUILTIN(__builtin_wasm_narrow_s_i8x16_i16x8, "V16cV8sV8s", "nc", "simd128")
+TARGET_BUILTIN(__builtin_wasm_narrow_u_i8x16_i16x8, "V16cV8sV8s", "nc", "simd128")
+TARGET_BUILTIN(__builtin_wasm_narrow_s_i16x8_i32x4, "V8sV4iV4i", "nc", "simd128")
+TARGET_BUILTIN(__builtin_wasm_narrow_u_i16x8_i32x4, "V8sV4iV4i", "nc", "simd128")
+
+TARGET_BUILTIN(__builtin_wasm_widen_low_s_i16x8_i8x16, "V8sV16c", "nc", "simd128")
+TARGET_BUILTIN(__builtin_wasm_widen_high_s_i16x8_i8x16, "V8sV16c", "nc", "simd128")
+TARGET_BUILTIN(__builtin_wasm_widen_low_u_i16x8_i8x16, "V8sV16c", "nc", "simd128")
+TARGET_BUILTIN(__builtin_wasm_widen_high_u_i16x8_i8x16, "V8sV16c", "nc", "simd128")
+TARGET_BUILTIN(__builtin_wasm_widen_low_s_i32x4_i16x8, "V4iV8s", "nc", "simd128")
+TARGET_BUILTIN(__builtin_wasm_widen_high_s_i32x4_i16x8, "V4iV8s", "nc", "simd128")
+TARGET_BUILTIN(__builtin_wasm_widen_low_u_i32x4_i16x8, "V4iV8s", "nc", "simd128")
+TARGET_BUILTIN(__builtin_wasm_widen_high_u_i32x4_i16x8, "V4iV8s", "nc", "simd128")
+
#undef BUILTIN
#undef TARGET_BUILTIN
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index a0ba0ecf36bb..5ab9dc1c3ac3 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -751,8 +751,8 @@ TARGET_BUILTIN(__builtin_ia32_bextri_u32, "UiUiIUi", "nc", "tbm")
// LWP
TARGET_BUILTIN(__builtin_ia32_llwpcb, "vv*", "n", "lwp")
TARGET_BUILTIN(__builtin_ia32_slwpcb, "v*", "n", "lwp")
-TARGET_BUILTIN(__builtin_ia32_lwpins32, "UcUiUiUi", "n", "lwp")
-TARGET_BUILTIN(__builtin_ia32_lwpval32, "vUiUiUi", "n", "lwp")
+TARGET_BUILTIN(__builtin_ia32_lwpins32, "UcUiUiIUi", "n", "lwp")
+TARGET_BUILTIN(__builtin_ia32_lwpval32, "vUiUiIUi", "n", "lwp")
// SHA
TARGET_BUILTIN(__builtin_ia32_sha1rnds4, "V4iV4iV4iIc", "ncV:128:", "sha")
diff --git a/include/clang/Basic/BuiltinsX86_64.def b/include/clang/Basic/BuiltinsX86_64.def
index 56051af55e7d..c535f43203e5 100644
--- a/include/clang/Basic/BuiltinsX86_64.def
+++ b/include/clang/Basic/BuiltinsX86_64.def
@@ -86,8 +86,8 @@ TARGET_BUILTIN(__builtin_ia32_bzhi_di, "UOiUOiUOi", "nc", "bmi2")
TARGET_BUILTIN(__builtin_ia32_pdep_di, "UOiUOiUOi", "nc", "bmi2")
TARGET_BUILTIN(__builtin_ia32_pext_di, "UOiUOiUOi", "nc", "bmi2")
TARGET_BUILTIN(__builtin_ia32_bextri_u64, "UOiUOiIUOi", "nc", "tbm")
-TARGET_BUILTIN(__builtin_ia32_lwpins64, "UcUOiUiUi", "n", "lwp")
-TARGET_BUILTIN(__builtin_ia32_lwpval64, "vUOiUiUi", "n", "lwp")
+TARGET_BUILTIN(__builtin_ia32_lwpins64, "UcUOiUiIUi", "n", "lwp")
+TARGET_BUILTIN(__builtin_ia32_lwpval64, "vUOiUiIUi", "n", "lwp")
TARGET_BUILTIN(__builtin_ia32_vcvtsd2si64, "OiV2dIi", "ncV:128:", "avx512f")
TARGET_BUILTIN(__builtin_ia32_vcvtsd2usi64, "UOiV2dIi", "ncV:128:", "avx512f")
TARGET_BUILTIN(__builtin_ia32_vcvtss2si64, "OiV4fIi", "ncV:128:", "avx512f")
diff --git a/include/clang/Basic/CodeGenOptions.def b/include/clang/Basic/CodeGenOptions.def
index cd7a84548765..d2266cc2d613 100644
--- a/include/clang/Basic/CodeGenOptions.def
+++ b/include/clang/Basic/CodeGenOptions.def
@@ -47,7 +47,8 @@ CODEGENOPT(CXXCtorDtorAliases, 1, 0) ///< Emit complete ctors/dtors as linker
///< aliases to base ctors when possible.
CODEGENOPT(DataSections , 1, 0) ///< Set when -fdata-sections is enabled.
CODEGENOPT(UniqueSectionNames, 1, 1) ///< Set for -funique-section-names.
-CODEGENOPT(DisableFPElim , 1, 0) ///< Set when -fomit-frame-pointer is enabled.
+ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None) /// frame-pointer: all,non-leaf,none
+
CODEGENOPT(DisableFree , 1, 0) ///< Don't free memory.
CODEGENOPT(DiscardValueNames , 1, 0) ///< Discard Value Names from the IR (LLVMContext flag)
CODEGENOPT(DisableGCov , 1, 0) ///< Don't run the GCov pass, for testing.
@@ -132,6 +133,7 @@ CODEGENOPT(NoDwarfDirectoryAsm , 1, 0) ///< Set when -fno-dwarf-directory-asm is
CODEGENOPT(NoExecStack , 1, 0) ///< Set when -Wa,--noexecstack is enabled.
CODEGENOPT(FatalWarnings , 1, 0) ///< Set when -Wa,--fatal-warnings is
///< enabled.
+CODEGENOPT(NoWarn , 1, 0) ///< Set when -Wa,--no-warn is enabled.
CODEGENOPT(EnableSegmentedStacks , 1, 0) ///< Set when -fsplit-stack is enabled.
CODEGENOPT(NoImplicitFloat , 1, 0) ///< Set when -mno-implicit-float is enabled.
CODEGENOPT(NoInfsFPMath , 1, 0) ///< Assume FP arguments, results not +-Inf.
@@ -155,8 +157,6 @@ CODEGENOPT(NoZeroInitializedInBSS , 1, 0) ///< -fno-zero-initialized-in-bss.
ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy)
/// Replace certain message sends with calls to ObjC runtime entrypoints
CODEGENOPT(ObjCConvertMessagesToRuntimeCalls , 1, 1)
-CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is
- ///< enabled.
VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified.
VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified.
@@ -195,6 +195,8 @@ CODEGENOPT(SanitizeMinimalRuntime, 1, 0) ///< Use "_minimal" sanitizer runtime f
///< diagnostics.
CODEGENOPT(SanitizeCfiICallGeneralizePointers, 1, 0) ///< Generalize pointer types in
///< CFI icall function signatures
+CODEGENOPT(SanitizeCfiCanonicalJumpTables, 1, 0) ///< Make jump table symbols canonical
+ ///< instead of creating a local jump table.
CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage
///< instrumentation.
CODEGENOPT(SanitizeCoverageIndirectCalls, 1, 0) ///< Enable sanitizer coverage
@@ -226,6 +228,8 @@ CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definiti
CODEGENOPT(StrictVTablePointers, 1, 0) ///< Optimize based on the strict vtable pointers
CODEGENOPT(TimePasses , 1, 0) ///< Set when -ftime-report is enabled.
CODEGENOPT(TimeTrace , 1, 0) ///< Set when -ftime-trace is enabled.
+VALUE_CODEGENOPT(TimeTraceGranularity, 32, 500) ///< Minimum time granularity (in microseconds),
+ ///< traced by time profiler
CODEGENOPT(UnrollLoops , 1, 0) ///< Control whether loops are unrolled.
CODEGENOPT(RerollLoops , 1, 0) ///< Control whether loops are rerolled.
CODEGENOPT(NoUseJumpTables , 1, 0) ///< Set when -fno-jump-tables is enabled.
@@ -274,6 +278,10 @@ CODEGENOPT(EmitLLVMUseLists, 1, 0) ///< Control whether to serialize use-lists.
CODEGENOPT(WholeProgramVTables, 1, 0) ///< Whether to apply whole-program
/// vtable optimization.
+CODEGENOPT(VirtualFunctionElimination, 1, 0) ///< Whether to apply the dead
+ /// virtual function elimination
+ /// optimization.
+
/// Whether to use public LTO visibility for entities in std and stdext
/// namespaces. This is enabled by clang-cl's /MT and /MTd flags.
CODEGENOPT(LTOVisibilityPublicStd, 1, 0)
diff --git a/include/clang/Basic/CodeGenOptions.h b/include/clang/Basic/CodeGenOptions.h
index 4e9025d2fea9..8881a316d1fb 100644
--- a/include/clang/Basic/CodeGenOptions.h
+++ b/include/clang/Basic/CodeGenOptions.h
@@ -117,6 +117,12 @@ public:
enum SignReturnAddressKeyValue { AKey, BKey };
+ enum class FramePointerKind {
+ None, // Omit all frame pointers.
+ NonLeaf, // Keep non-leaf frame pointers.
+ All, // Keep all frame pointers.
+ };
+
/// The code model to use (-mcmodel).
std::string CodeModel;
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 5a707007e463..9e494aa371cd 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -632,24 +632,22 @@ public:
/// Suppress all diagnostics, to silence the front end when we
/// know that we don't want any more diagnostics to be passed along to the
/// client
- void setSuppressAllDiagnostics(bool Val = true) {
- SuppressAllDiagnostics = Val;
- }
+ void setSuppressAllDiagnostics(bool Val) { SuppressAllDiagnostics = Val; }
bool getSuppressAllDiagnostics() const { return SuppressAllDiagnostics; }
/// Set type eliding, to skip outputting same types occurring in
/// template types.
- void setElideType(bool Val = true) { ElideType = Val; }
+ void setElideType(bool Val) { ElideType = Val; }
bool getElideType() { return ElideType; }
/// Set tree printing, to outputting the template difference in a
/// tree format.
- void setPrintTemplateTree(bool Val = false) { PrintTemplateTree = Val; }
+ void setPrintTemplateTree(bool Val) { PrintTemplateTree = Val; }
bool getPrintTemplateTree() { return PrintTemplateTree; }
/// Set color printing, so the type diffing will inject color markers
/// into the output.
- void setShowColors(bool Val = false) { ShowColors = Val; }
+ void setShowColors(bool Val) { ShowColors = Val; }
bool getShowColors() { return ShowColors; }
/// Specify which overload candidates to show when overload resolution
@@ -667,7 +665,7 @@ public:
/// the middle of another diagnostic.
///
/// This can be used by clients who suppress diagnostics themselves.
- void setLastDiagnosticIgnored(bool Ignored = true) {
+ void setLastDiagnosticIgnored(bool Ignored) {
if (LastDiagLevel == DiagnosticIDs::Fatal)
FatalErrorOccurred = true;
LastDiagLevel = Ignored ? DiagnosticIDs::Ignored : DiagnosticIDs::Warning;
@@ -1127,11 +1125,6 @@ public:
Emit();
}
- /// Retrieve an empty diagnostic builder.
- static DiagnosticBuilder getEmpty() {
- return {};
- }
-
/// Forces the diagnostic to be emitted.
const DiagnosticBuilder &setForceEmit() const {
IsForceEmit = true;
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index 23502152b4ac..04d767445a8f 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -37,8 +37,9 @@ def note_constexpr_virtual_call : Note<
def note_constexpr_pure_virtual_call : Note<
"pure virtual function %q0 called">;
def note_constexpr_polymorphic_unknown_dynamic_type : Note<
- "%select{||||virtual function called on|dynamic_cast applied to|"
- "typeid applied to}0 object '%1' whose dynamic type is not constant">;
+ "%select{|||||virtual function called on|dynamic_cast applied to|"
+ "typeid applied to|construction of|destruction of}0 object '%1' "
+ "whose dynamic type is not constant">;
def note_constexpr_dynamic_cast_to_reference_failed : Note<
"reference dynamic_cast failed: %select{"
"static type %1 of operand is a non-public base class of dynamic type %2|"
@@ -53,6 +54,9 @@ def note_constexpr_nonliteral : Note<
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_dynamic_alloc : Note<
+ "%select{pointer|reference}0 to %select{|subobject of }1"
+ "heap-allocated object is not a constant expression">;
def note_constexpr_uninitialized : Note<
"%select{|sub}0object of type %1 is not initialized">;
def note_constexpr_subobject_declared_here : Note<
@@ -100,6 +104,7 @@ def note_constexpr_typeid_polymorphic : Note<
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_dynamic_alloc_here : Note<"heap allocation performed here">;
def note_constexpr_conditional_never_const : Note<
"both arms of conditional operator are unable to produce a "
"constant expression">;
@@ -109,16 +114,20 @@ def note_constexpr_call_limit_exceeded : Note<
"constexpr evaluation hit maximum call limit">;
def note_constexpr_step_limit_exceeded : Note<
"constexpr evaluation hit maximum step limit; possible infinite loop?">;
+def note_constexpr_heap_alloc_limit_exceeded : Note<
+ "constexpr evaluation hit maximum heap allocation limit">;
def note_constexpr_this : Note<
"%select{|implicit }0use of 'this' pointer is only allowed within the "
"evaluation of a call to a 'constexpr' member function">;
def note_constexpr_lifetime_ended : Note<
- "%select{read of|assignment to|increment of|decrement of|member call on|"
- "dynamic_cast of|typeid applied to}0 "
- "%select{temporary|variable}1 whose lifetime has ended">;
+ "%select{read of|read of|assignment to|increment of|decrement of|"
+ "member call on|dynamic_cast of|typeid applied to|construction of|"
+ "destruction of}0 %select{temporary|variable}1 whose "
+ "%plural{8:storage duration|:lifetime}0 has ended">;
def note_constexpr_access_uninit : Note<
- "%select{read of|assignment to|increment of|decrement of|member call on|"
- "dynamic_cast of|typeid applied to}0 "
+ "%select{read of|read of|assignment to|increment of|decrement of|"
+ "member call on|dynamic_cast of|typeid applied to|"
+ "construction of subobject of|destruction of}0 "
"%select{object outside its lifetime|uninitialized object}1 "
"is not allowed in a constant expression">;
def note_constexpr_use_uninit_reference : Note<
@@ -128,16 +137,21 @@ def note_constexpr_modify_const_type : Note<
"modification of object of const-qualified type %0 is not allowed "
"in a constant expression">;
def note_constexpr_access_volatile_type : Note<
- "%select{read of|assignment to|increment of|decrement of|<ERROR>|<ERROR>}0 "
+ "%select{read of|read of|assignment to|increment of|decrement of|"
+ "<ERROR>|<ERROR>|<ERROR>|<ERROR>}0 "
"volatile-qualified type %1 is not allowed in a constant expression">;
def note_constexpr_access_volatile_obj : Note<
- "%select{read of|assignment to|increment of|decrement of|<ERROR>|<ERROR>}0 "
+ "%select{read of|read of|assignment to|increment of|decrement of|"
+ "<ERROR>|<ERROR>|<ERROR>|<ERROR>}0 "
"volatile %select{temporary|object %2|member %2}1 is not allowed in "
"a constant expression">;
def note_constexpr_volatile_here : Note<
"volatile %select{temporary created|object declared|member declared}0 here">;
-def note_constexpr_ltor_mutable : Note<
- "read of mutable member %0 is not allowed in a constant expression">;
+def note_constexpr_access_mutable : Note<
+ "%select{read of|read of|assignment to|increment of|decrement of|"
+ "member call on|dynamic_cast of|typeid applied to|construction of|"
+ "destruction of}0 "
+ "mutable member %1 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<
@@ -145,31 +159,44 @@ def note_constexpr_ltor_non_constexpr : Note<
def note_constexpr_ltor_incomplete_type : Note<
"read of incomplete type %0 is not allowed in a constant expression">;
def note_constexpr_access_null : Note<
- "%select{read of|assignment to|increment of|decrement of|member call on|"
- "dynamic_cast of|typeid applied to}0 "
+ "%select{read of|read of|assignment to|increment of|decrement of|"
+ "member call on|dynamic_cast of|typeid applied to|construction of|"
+ "destruction of}0 "
"dereferenced null pointer is not allowed in a constant expression">;
def note_constexpr_access_past_end : Note<
- "%select{read of|assignment to|increment of|decrement of|member call on|"
- "dynamic_cast of|typeid applied to}0 "
- "dereferenced one-past-the-end pointer is not allowed in a constant expression">;
+ "%select{read of|read of|assignment to|increment of|decrement of|"
+ "member call on|dynamic_cast of|typeid applied to|construction of|"
+ "destruction of}0 "
+ "dereferenced one-past-the-end pointer is not allowed "
+ "in a constant expression">;
def note_constexpr_access_unsized_array : Note<
- "%select{read of|assignment to|increment of|decrement of|member call on|"
- "dynamic_cast of|typeid applied to}0 "
+ "%select{read of|read of|assignment to|increment of|decrement of|"
+ "member call on|dynamic_cast of|typeid applied to|construction of|"
+ "destruction of}0 "
"element of array without known bound "
"is not allowed in a constant expression">;
def note_constexpr_access_inactive_union_member : Note<
- "%select{read of|assignment to|increment of|decrement of|member call on|"
- "dynamic_cast of|typeid applied to}0 "
+ "%select{read of|read of|assignment to|increment of|decrement of|"
+ "member call on|dynamic_cast of|typeid applied to|"
+ "construction of subobject of|destruction of}0 "
"member %1 of union with %select{active member %3|no active member}2 "
"is not allowed in a constant expression">;
def note_constexpr_access_static_temporary : Note<
- "%select{read of|assignment to|increment of|decrement of|member call on|"
- "dynamic_cast of|typeid applied to}0 temporary "
+ "%select{read of|read of|assignment to|increment of|decrement of|"
+ "member call on|dynamic_cast of|typeid applied to|reconstruction of|"
+ "destruction of}0 temporary "
"is not allowed in a constant expression outside the expression that "
"created the temporary">;
def note_constexpr_access_unreadable_object : Note<
- "%select{read of|assignment to|increment of|decrement of|member call on|"
- "dynamic_cast of|typeid applied to}0 object '%1' whose value is not known">;
+ "%select{read of|read of|assignment to|increment of|decrement of|"
+ "member call on|dynamic_cast of|typeid applied to|construction of|"
+ "destruction of}0 "
+ "object '%1' whose value is not known">;
+def note_constexpr_access_deleted_object : Note<
+ "%select{read of|read of|assignment to|increment of|decrement of|"
+ "member call on|dynamic_cast of|typeid applied to|construction of|"
+ "destruction of}0 "
+ "heap allocated object that has been deleted">;
def note_constexpr_modify_global : Note<
"a constant expression cannot modify an object that is visible outside "
"that expression">;
@@ -189,6 +216,13 @@ def note_constexpr_baa_insufficient_alignment : Note<
def note_constexpr_baa_value_insufficient_alignment : Note<
"value of the aligned pointer (%0) is not a multiple of the asserted %1 "
"%plural{1:byte|:bytes}1">;
+def note_constexpr_destroy_out_of_lifetime : Note<
+ "destroying object '%0' whose lifetime has already ended">;
+def note_constexpr_unsupported_destruction : Note<
+ "non-trivial destruction of type %0 in a constant expression is not supported">;
+def note_constexpr_unsupported_tempoarary_nontrivial_dtor : Note<
+ "non-trivial destruction of lifetime-extended temporary with type %0 "
+ "used in the result of a constant expression is not yet supported">;
def note_constexpr_unsupported_unsized_array : Note<
"array-to-pointer decay of array member without known bound is not supported">;
def note_constexpr_unsized_array_indexed : Note<
@@ -228,6 +262,62 @@ def note_constexpr_bit_cast_invalid_subtype : Note<
def note_constexpr_bit_cast_indet_dest : Note<
"indeterminate value can only initialize an object of type 'unsigned char'"
"%select{, 'char',|}1 or 'std::byte'; %0 is invalid">;
+def note_constexpr_pseudo_destructor : Note<
+ "pseudo-destructor call is not permitted in constant expressions "
+ "until C++20">;
+def note_constexpr_construct_complex_elem : Note<
+ "construction of individual component of complex number is not yet supported "
+ "in constant expressions">;
+def note_constexpr_destroy_complex_elem : Note<
+ "destruction of individual component of complex number is not yet supported "
+ "in constant expressions">;
+def note_constexpr_new : Note<
+ "dynamic memory allocation is not permitted in constant expressions "
+ "until C++20">;
+def note_constexpr_new_non_replaceable : Note<
+ "call to %select{placement|class-specific}0 %1">;
+def note_constexpr_new_placement : Note<
+ "this placement new expression is not yet supported in constant expressions">;
+def note_constexpr_placement_new_wrong_type : Note<
+ "placement new would change type of storage from %0 to %1">;
+def note_constexpr_new_negative : Note<
+ "cannot allocate array; evaluated array bound %0 is negative">;
+def note_constexpr_new_too_large : Note<
+ "cannot allocate array; evaluated array bound %0 is too large">;
+def note_constexpr_new_too_small : Note<
+ "cannot allocate array; evaluated array bound %0 is too small to hold "
+ "%1 explicitly initialized elements">;
+def note_constexpr_new_untyped : Note<
+ "cannot allocate untyped memory in a constant expression; "
+ "use 'std::allocator<T>::allocate' to allocate memory of type 'T'">;
+def note_constexpr_new_not_complete_object_type : Note<
+ "cannot allocate memory of %select{incomplete|function}0 type %1">;
+def note_constexpr_operator_new_bad_size : Note<
+ "allocated size %0 is not a multiple of size %1 of element type %2">;
+def note_constexpr_delete_not_heap_alloc : Note<
+ "delete of pointer '%0' that does not point to a heap-allocated object">;
+def note_constexpr_double_delete : Note<
+ "delete of pointer that has already been deleted">;
+def note_constexpr_double_destroy : Note<
+ "destruction of object that is already being destroyed">;
+def note_constexpr_new_delete_mismatch : Note<
+ "%plural{2:'delete' used to delete pointer to object "
+ "allocated with 'std::allocator<...>::allocate'|"
+ ":%select{non-array delete|array delete|'std::allocator<...>::deallocate'}0 "
+ "used to delete pointer to "
+ "%select{array object of type %2|non-array object of type %2|"
+ "object allocated with 'new'}0}1">;
+def note_constexpr_delete_subobject : Note<
+ "delete of pointer%select{ to subobject|}1 '%0' "
+ "%select{|that does not point to complete object}1">;
+def note_constexpr_delete_base_nonvirt_dtor : Note<
+ "delete of object with dynamic type %1 through pointer to "
+ "base class type %0 with non-virtual destructor">;
+def note_constexpr_memory_leak : Note<
+ "allocation performed here was not deallocated"
+ "%plural{0:|: (along with %0 other memory leak%s0)}0">;
+def err_experimental_clang_interp_failed : Error<
+ "the experimental clang interpreter failed to evaluate an expression">;
def warn_integer_constant_overflow : Warning<
"overflow in expression; result is %0 with type %1">,
@@ -277,7 +367,6 @@ def warn_odr_variable_multiple_def : Warning<
"external variable %0 defined in multiple translation units">,
InGroup<ODR>;
def note_odr_value_here : Note<"declared here with type %0">;
-def note_odr_defined_here : Note<"also defined here">;
def err_odr_function_type_inconsistent : Error<
"external function %0 declared with incompatible types in different "
"translation units (%1 vs. %2)">;
diff --git a/include/clang/Basic/DiagnosticCommentKinds.td b/include/clang/Basic/DiagnosticCommentKinds.td
index fcda3f3a2113..c577ac408539 100644
--- a/include/clang/Basic/DiagnosticCommentKinds.td
+++ b/include/clang/Basic/DiagnosticCommentKinds.td
@@ -153,6 +153,12 @@ def warn_doc_deprecated_not_sync : Warning<
def note_add_deprecation_attr : Note<
"add a deprecation attribute to the declaration to silence this warning">;
+// inline contents commands
+
+def warn_doc_inline_contents_no_argument : Warning<
+ "'%select{\\|@}0%1' command does not have a valid word argument">,
+ InGroup<Documentation>, DefaultIgnore;
+
// verbatim block commands
def warn_verbatim_block_end_without_start : Warning<
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index ca2faf59d70f..484cc317f965 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -12,11 +12,21 @@
let Component = "Common" in {
+// Substitutions.
+
+def select_constexpr_spec_kind : TextSubstitution<
+ "%select{<ERROR>|constexpr|consteval|constinit}0">;
+
// Basic.
def fatal_too_many_errors
: Error<"too many errors emitted, stopping now">, DefaultFatal;
+def warn_stack_exhausted : Warning<
+ "stack nearly exhausted; compilation time may suffer, and "
+ "crashes due to stack overflow are likely">,
+ InGroup<DiagGroup<"stack-exhausted">>, NoSFINAE;
+
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">;
@@ -107,6 +117,10 @@ def err_attribute_not_type_attr : Error<
"%0 attribute cannot be applied to types">;
def err_enum_template : Error<"enumeration cannot be a template">;
+def warn_cxx20_compat_consteval : Warning<
+ "'consteval' specifier is incompatible with C++ standards before C++20">,
+ InGroup<CXX2aCompat>, DefaultIgnore;
+
}
let CategoryName = "Nullability Issue" in {
@@ -172,9 +186,6 @@ def ext_cxx11_longlong : Extension<
def warn_cxx98_compat_longlong : Warning<
"'long long' is incompatible with C++98">,
InGroup<CXX98CompatPedantic>, DefaultIgnore;
-def warn_cxx20_compat_consteval : Warning<
- "consteval is incompatible with C++ standards before C++20">,
- InGroup<CXX2aCompat>, DefaultIgnore;
def err_integer_literal_too_large : Error<
"integer literal is too large to be represented in any %select{signed |}0"
"integer type">;
@@ -259,8 +270,6 @@ def err_target_unsupported_mcmse : Error<
"-mcmse is not supported for %0">;
def err_opt_not_valid_with_opt : Error<
"option '%0' cannot be specified with '%1'">;
-def err_opt_not_valid_without_opt : Error<
- "option '%0' cannot be specified without '%1'">;
def err_opt_not_valid_on_target : Error<
"option '%0' cannot be specified on this target">;
@@ -300,8 +309,13 @@ def err_omp_more_one_clause : Error<
"directive '#pragma omp %0' cannot contain more than one '%1' clause%select{| with '%3' name modifier| with 'source' dependence}2">;
// Static Analyzer Core
-def err_unknown_analyzer_checker : Error<
+def err_unknown_analyzer_checker_or_package : Error<
"no analyzer checkers or packages are associated with '%0'">;
def note_suggest_disabling_all_checkers : Note<
"use -analyzer-disable-all-checks to disable all static analyzer checkers">;
+
+// Poison system directories.
+def warn_poison_system_directories : Warning <
+ "include location '%0' is unsafe for cross-compilation">,
+ InGroup<DiagGroup<"poison-system-directories">>, DefaultIgnore;
}
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index eab453ee20ec..5ff03e133563 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -184,9 +184,6 @@ def warn_drv_unknown_argument_clang_cl_with_suggestion : Warning<
def warn_drv_ycyu_different_arg_clang_cl : Warning<
"support for '/Yc' and '/Yu' with different filenames not implemented yet; flags ignored">,
InGroup<ClangClPch>;
-def warn_drv_ycyu_no_fi_arg_clang_cl : Warning<
- "support for '%0' without a corresponding /FI flag not implemented yet; flag ignored">,
- InGroup<ClangClPch>;
def warn_drv_yc_multiple_inputs_clang_cl : Warning<
"support for '/Yc' with more than one source file not implemented yet; flag ignored">,
InGroup<ClangClPch>;
@@ -368,6 +365,9 @@ def err_drv_ropi_rwpi_incompatible_with_pic : Error<
def err_drv_ropi_incompatible_with_cxx : Error<
"ROPI is not compatible with c++">;
+def err_stack_tagging_requires_hardware_feature : Error<
+ "'-fsanitize=memtag' requires hardware support (+memtag)">;
+
def warn_target_unsupported_nan2008 : Warning<
"ignoring '-mnan=2008' option because the '%0' architecture does not support it">,
InGroup<UnsupportedNan>;
@@ -383,6 +383,9 @@ def warn_target_unsupported_abs2008 : Warning<
def warn_target_unsupported_compact_branches : Warning<
"ignoring '-mcompact-branches=' option because the '%0' architecture does not"
" support it">, InGroup<UnsupportedCB>;
+def warn_target_unsupported_extension : Warning<
+ "ignoring extension '%0' because the '%1' architecture does not support it">,
+ InGroup<InvalidCommandLineArgument>;
def warn_drv_unsupported_gpopt : Warning<
"ignoring '-mgpopt' option as it cannot be used with %select{|the implicit"
" usage of }0-mabicalls">,
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 7a990164b0d9..a798b498d4e9 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -64,8 +64,6 @@ def err_fe_backend_unsupported : Error<"%0">, BackendInfo;
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_dependency_file_requires_MT : Error<
"-dependency-file requires at least one -MT or -MQ option">;
def err_fe_invalid_plugin_name : Error<
@@ -217,10 +215,6 @@ def err_modules_embed_file_not_found :
DefaultFatal;
def err_module_header_file_not_found :
Error<"module header file '%0' not found">, DefaultFatal;
-def err_module_header_file_invalid :
- Error<"unexpected module header file input '%0'">, DefaultFatal;
-
-def err_interface_stubs : Error<"clang-ifs (-emit-iterface-stubs): %0">;
def err_test_module_file_extension_version : Error<
"test module file extension '%0' has different version (%1.%2) than expected "
@@ -275,7 +269,12 @@ def warn_profile_data_missing : Warning<
def warn_profile_data_unprofiled : Warning<
"no profile data available for file \"%0\"">,
InGroup<ProfileInstrUnprofiled>;
-
+def warn_profile_data_misexpect : Warning<
+ "Potential performance regression from use of __builtin_expect(): "
+ "Annotation was correct on %0 of profiled executions.">,
+ BackendInfo,
+ InGroup<MisExpect>,
+ DefaultIgnore;
} // end of instrumentation issue category
}
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 56f2ecfe8e4a..928059539558 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -61,8 +61,16 @@ def BoolConversion : DiagGroup<"bool-conversion", [PointerBoolConversion,
UndefinedBoolConversion]>;
def IntConversion : DiagGroup<"int-conversion">;
def EnumConversion : DiagGroup<"enum-conversion">;
-def ImplicitIntConversion : DiagGroup<"implicit-int-conversion">;
-def ImplicitFloatConversion : DiagGroup<"implicit-float-conversion">;
+def ObjCSignedCharBoolImplicitIntConversion :
+ DiagGroup<"objc-signed-char-bool-implicit-int-conversion">;
+def ImplicitIntConversion : DiagGroup<"implicit-int-conversion",
+ [ObjCSignedCharBoolImplicitIntConversion]>;
+def ImplicitIntFloatConversion : DiagGroup<"implicit-int-float-conversion">;
+def ObjCSignedCharBoolImplicitFloatConversion :
+ DiagGroup<"objc-signed-char-bool-implicit-float-conversion">;
+def ImplicitFloatConversion : DiagGroup<"implicit-float-conversion",
+ [ImplicitIntFloatConversion,
+ ObjCSignedCharBoolImplicitFloatConversion]>;
def ImplicitFixedPointConversion : DiagGroup<"implicit-fixed-point-conversion">;
def FloatOverflowConversion : DiagGroup<"float-overflow-conversion">;
@@ -99,7 +107,6 @@ def GNUComplexInteger : DiagGroup<"gnu-complex-integer">;
def GNUConditionalOmittedOperand : DiagGroup<"gnu-conditional-omitted-operand">;
def ConfigMacros : DiagGroup<"config-macros">;
def : DiagGroup<"ctor-dtor-privacy">;
-def GNUDesignator : DiagGroup<"gnu-designator">;
def GNUStringLiteralOperatorTemplate :
DiagGroup<"gnu-string-literal-operator-template">;
def UndefinedVarTemplate : DiagGroup<"undefined-var-template">;
@@ -113,11 +120,13 @@ def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor",
[DeleteNonAbstractNonVirtualDtor,
DeleteAbstractNonVirtualDtor]>;
def AbstractFinalClass : DiagGroup<"abstract-final-class">;
+def FinalDtorNonFinalClass : DiagGroup<"final-dtor-non-final-class">;
def CXX11CompatDeprecatedWritableStr :
DiagGroup<"c++11-compat-deprecated-writable-strings">;
def DeprecatedAttributes : DiagGroup<"deprecated-attributes">;
+def DeprecatedCommaSubscript : DiagGroup<"deprecated-comma-subscript">;
def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
def UnavailableDeclarations : DiagGroup<"unavailable-declarations">;
def UnguardedAvailabilityNew : DiagGroup<"unguarded-availability-new">;
@@ -131,18 +140,27 @@ def DeprecatedImplementations :DiagGroup<"deprecated-implementations">;
def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">;
def DeprecatedRegister : DiagGroup<"deprecated-register">;
def DeprecatedThisCapture : DiagGroup<"deprecated-this-capture">;
+def DeprecatedVolatile : DiagGroup<"deprecated-volatile">;
def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings",
[CXX11CompatDeprecatedWritableStr]>;
// FIXME: Why is DeprecatedImplementations not in this group?
def Deprecated : DiagGroup<"deprecated", [DeprecatedAttributes,
+ DeprecatedCommaSubscript,
DeprecatedDeclarations,
DeprecatedDynamicExceptionSpec,
DeprecatedIncrementBool,
DeprecatedRegister,
DeprecatedThisCapture,
+ DeprecatedVolatile,
DeprecatedWritableStr]>,
DiagCategory<"Deprecations">;
+def CXX2aDesignator : DiagGroup<"c++2a-designator">;
+// Allow -Wno-c99-designator to be used to turn off all warnings on valid C99
+// designators (including the warning controlled by -Wc++2a-designator).
+def C99Designator : DiagGroup<"c99-designator", [CXX2aDesignator]>;
+def GNUDesignator : DiagGroup<"gnu-designator">;
+
def DynamicExceptionSpec
: DiagGroup<"dynamic-exception-spec", [DeprecatedDynamicExceptionSpec]>;
@@ -278,6 +296,7 @@ def ExitTimeDestructors : DiagGroup<"exit-time-destructors">;
def FlexibleArrayExtensions : DiagGroup<"flexible-array-extensions">;
def FourByteMultiChar : DiagGroup<"four-char-constants">;
def GlobalConstructors : DiagGroup<"global-constructors">;
+def BitwiseConditionalParentheses: DiagGroup<"bitwise-conditional-parentheses">;
def BitwiseOpParentheses: DiagGroup<"bitwise-op-parentheses">;
def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">;
def LogicalNotParentheses: DiagGroup<"logical-not-parentheses">;
@@ -286,9 +305,11 @@ def OverloadedShiftOpParentheses: DiagGroup<"overloaded-shift-op-parentheses">;
def DanglingElse: DiagGroup<"dangling-else">;
def DanglingField : DiagGroup<"dangling-field">;
def DanglingInitializerList : DiagGroup<"dangling-initializer-list">;
+def DanglingGsl : DiagGroup<"dangling-gsl">;
def ReturnStackAddress : DiagGroup<"return-stack-address">;
def Dangling : DiagGroup<"dangling", [DanglingField,
DanglingInitializerList,
+ DanglingGsl,
ReturnStackAddress]>;
def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">;
def ExpansionToDefined : DiagGroup<"expansion-to-defined">;
@@ -481,6 +502,7 @@ def StringCompare : DiagGroup<"string-compare">;
def StringPlusInt : DiagGroup<"string-plus-int">;
def StringPlusChar : DiagGroup<"string-plus-char">;
def StrncatSize : DiagGroup<"strncat-size">;
+def IntInBoolContext : DiagGroup<"int-in-bool-context">;
def TautologicalTypeLimitCompare : DiagGroup<"tautological-type-limit-compare">;
def TautologicalUnsignedZeroCompare : DiagGroup<"tautological-unsigned-zero-compare">;
def TautologicalUnsignedEnumZeroCompare : DiagGroup<"tautological-unsigned-enum-zero-compare">;
@@ -495,12 +517,14 @@ def TautologicalConstantCompare : DiagGroup<"tautological-constant-compare",
[TautologicalOutOfRangeCompare]>;
def TautologicalPointerCompare : DiagGroup<"tautological-pointer-compare">;
def TautologicalOverlapCompare : DiagGroup<"tautological-overlap-compare">;
+def TautologicalBitwiseCompare : DiagGroup<"tautological-bitwise-compare">;
def TautologicalUndefinedCompare : DiagGroup<"tautological-undefined-compare">;
def TautologicalObjCBoolCompare : DiagGroup<"tautological-objc-bool-compare">;
def TautologicalCompare : DiagGroup<"tautological-compare",
[TautologicalConstantCompare,
TautologicalPointerCompare,
TautologicalOverlapCompare,
+ TautologicalBitwiseCompare,
TautologicalUndefinedCompare,
TautologicalObjCBoolCompare]>;
def HeaderHygiene : DiagGroup<"header-hygiene">;
@@ -509,6 +533,7 @@ def CompareDistinctPointerType : DiagGroup<"compare-distinct-pointer-types">;
def GNUUnionCast : DiagGroup<"gnu-union-cast">;
def GNUVariableSizedTypeNotAtEnd : DiagGroup<"gnu-variable-sized-type-not-at-end">;
def Varargs : DiagGroup<"varargs">;
+def XorUsedAsPow : DiagGroup<"xor-used-as-pow">;
def Unsequenced : DiagGroup<"unsequenced">;
// GCC name for -Wunsequenced
@@ -543,6 +568,7 @@ def CoveredSwitchDefault : DiagGroup<"covered-switch-default">;
def SwitchBool : DiagGroup<"switch-bool">;
def SwitchEnum : DiagGroup<"switch-enum">;
def Switch : DiagGroup<"switch">;
+def EnumCompareConditional : DiagGroup<"enum-compare-conditional">;
def EnumCompareSwitch : DiagGroup<"enum-compare-switch">;
def EnumCompare : DiagGroup<"enum-compare", [EnumCompareSwitch]>;
def ImplicitFallthroughPerFunction :
@@ -620,7 +646,9 @@ def UnusedGetterReturnValue : DiagGroup<"unused-getter-return-value">;
def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">;
def UserDefinedLiterals : DiagGroup<"user-defined-literals">;
def UserDefinedWarnings : DiagGroup<"user-defined-warnings">;
-def Reorder : DiagGroup<"reorder">;
+def ReorderCtor : DiagGroup<"reorder-ctor">;
+def ReorderInitList : DiagGroup<"reorder-init-list">;
+def Reorder : DiagGroup<"reorder", [ReorderCtor, ReorderInitList]>;
def UndeclaredSelector : DiagGroup<"undeclared-selector">;
def ImplicitAtomic : DiagGroup<"implicit-atomic-properties">;
def CustomAtomic : DiagGroup<"custom-atomic-properties">;
@@ -710,6 +738,7 @@ def ParenthesesOnEquality : DiagGroup<"parentheses-equality">;
def Parentheses : DiagGroup<"parentheses",
[LogicalOpParentheses,
LogicalNotParentheses,
+ BitwiseConditionalParentheses,
BitwiseOpParentheses,
ShiftOpParentheses,
OverloadedShiftOpParentheses,
@@ -757,6 +786,7 @@ def FormatSecurity : DiagGroup<"format-security">;
def FormatNonStandard : DiagGroup<"format-non-iso">;
def FormatY2K : DiagGroup<"format-y2k">;
def FormatPedantic : DiagGroup<"format-pedantic">;
+def FormatTypeConfusion : DiagGroup<"format-type-confusion">;
def Format : DiagGroup<"format",
[FormatExtraArgs, FormatZeroLength, NonNull,
FormatSecurity, FormatY2K, FormatInvalidSpecifier]>,
@@ -800,6 +830,7 @@ def Most : DiagGroup<"most", [
Format,
Implicit,
InfiniteRecursion,
+ IntInBoolContext,
MismatchedTags,
MissingBraces,
Move,
@@ -890,7 +921,7 @@ def CXX17 : DiagGroup<"c++17-extensions">;
// A warning group for warnings about using C++2a features as extensions in
// earlier C++ versions.
-def CXX2a : DiagGroup<"c++2a-extensions">;
+def CXX2a : DiagGroup<"c++2a-extensions", [CXX2aDesignator]>;
def : DiagGroup<"c++0x-extensions", [CXX11]>;
def : DiagGroup<"c++1y-extensions", [CXX14]>;
@@ -903,7 +934,7 @@ def DelegatingCtorCycles :
def C11 : DiagGroup<"c11-extensions">;
// A warning group for warnings about using C99 features as extensions.
-def C99 : DiagGroup<"c99-extensions">;
+def C99 : DiagGroup<"c99-extensions", [C99Designator]>;
// A warning group for warnings about GCC extensions.
def GNU : DiagGroup<"gnu", [GNUAlignofExpression, GNUAnonymousStruct,
@@ -1001,6 +1032,12 @@ def ObjCLiteralComparison : DiagGroup<"objc-literal-compare", [
ObjCStringComparison
]>;
+def ObjCSignedCharBool : DiagGroup<"objc-signed-char-bool",
+ [ObjCSignedCharBoolImplicitIntConversion,
+ ObjCSignedCharBoolImplicitFloatConversion,
+ ObjCBoolConstantConversion,
+ TautologicalObjCBoolCompare]>;
+
// Inline ASM warnings.
def ASMOperandWidths : DiagGroup<"asm-operand-widths">;
def ASMIgnoredQualifier : DiagGroup<"asm-ignored-qualifier">;
@@ -1028,6 +1065,7 @@ def BackendOptimizationFailure : DiagGroup<"pass-failed">;
def ProfileInstrMissing : DiagGroup<"profile-instr-missing">;
def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">;
def ProfileInstrUnprofiled : DiagGroup<"profile-instr-unprofiled">;
+def MisExpect : DiagGroup<"misexpect">;
// AddressSanitizer frontend instrumentation remarks.
def SanitizeAddressRemarks : DiagGroup<"sanitize-address">;
diff --git a/include/clang/Basic/DiagnosticOptions.def b/include/clang/Basic/DiagnosticOptions.def
index baafd7ac723f..6d1a1af92821 100644
--- a/include/clang/Basic/DiagnosticOptions.def
+++ b/include/clang/Basic/DiagnosticOptions.def
@@ -49,6 +49,7 @@ DIAGOPT(Pedantic, 1, 0) /// -pedantic
DIAGOPT(PedanticErrors, 1, 0) /// -pedantic-errors
DIAGOPT(ShowColumn, 1, 1) /// Show column number on diagnostics.
DIAGOPT(ShowLocation, 1, 1) /// Show source location information.
+DIAGOPT(ShowLevel, 1, 1) /// Show diagnostic level.
DIAGOPT(AbsolutePath, 1, 0) /// Use absolute paths.
DIAGOPT(ShowCarets, 1, 1) /// Show carets in diagnostics.
DIAGOPT(ShowFixits, 1, 1) /// Show fixit information.
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 8e6ced0dea54..7c9f4da778a6 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -119,18 +119,16 @@ def warn_microsoft_qualifiers_ignored : Warning<
"qualifiers after comma in declarator list are ignored">,
InGroup<IgnoredAttributes>;
-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_c11_alignment : Extension<
- "%0 is a C11-specific feature">, InGroup<C11>;
+def ext_c99_feature : Extension<
+ "'%0' is a C99 extension">, InGroup<C99>;
+def ext_c11_feature : Extension<
+ "'%0' is a C11 extension">, InGroup<C11>;
-def ext_c11_noreturn : Extension<
- "_Noreturn functions are a C11-specific feature">, InGroup<C11>;
def err_c11_noreturn_misplaced : Error<
"'_Noreturn' keyword must precede function declarator">;
@@ -203,6 +201,7 @@ 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_lbrace_after : Error<"expected '{' after '%0'">;
def err_expected_rparen_after : Error<"expected ')' after '%0'">;
def err_expected_punc : Error<"expected ')' or ',' after '%0'">;
def err_expected_less_after : Error<"expected '<' after '%0'">;
@@ -360,7 +359,8 @@ def err_typename_invalid_storageclass : Error<
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 %select{constexpr|consteval}0 specifier to be specified">;
+ "type name does not allow %sub{select_constexpr_spec_kind}0 specifier "
+ "to be specified">;
def err_typename_identifiers_only : Error<
"typename is allowed for identifiers only">;
@@ -374,8 +374,6 @@ def err_unexpected_token_in_nested_name_spec : Error<
"'%0' cannot be a part of nested name specifier; did you mean ':'?">;
def err_bool_redeclaration : Error<
"redeclaration of C++ built-in type 'bool'">;
-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;
@@ -436,8 +434,6 @@ def err_objc_property_requires_field_name : Error<
"property requires fields to be named">;
def err_objc_property_bitfield : Error<"property name cannot be a bit-field">;
def err_objc_expected_property_attr : Error<"unknown property attribute %0">;
-def err_objc_properties_require_objc2 : Error<
- "properties are an Objective-C 2 feature">;
def err_objc_unexpected_attr : Error<
"prefix attribute must be followed by an interface, protocol, or implementation">;
def err_objc_postfix_attribute : Error <
@@ -976,11 +972,13 @@ def warn_pragma_missing_argument : Warning<
def warn_pragma_invalid_argument : Warning<
"unexpected argument '%0' to '#pragma %1'%select{|; expected %3}2">, InGroup<IgnoredPragmas>;
+def err_pragma_misplaced_in_decl : Error<"this pragma cannot appear in %0 declaration">;
+
// '#pragma clang section' related errors
def err_pragma_expected_clang_section_name : Error<
- "expected one of [bss|data|rodata|text] section kind in '#pragma %0'">;
+ "expected one of [bss|data|rodata|text|relro] section kind in '#pragma %0'">;
def err_pragma_clang_section_expected_equal : Error<
- "expected '=' following '#pragma clang section %select{invalid|bss|data|rodata|text}0'">;
+ "expected '=' following '#pragma clang section %select{invalid|bss|data|rodata|text|relro}0'">;
def warn_pragma_expected_section_name : Warning<
"expected a string literal for the section name in '#pragma %0' - ignored">,
InGroup<IgnoredPragmas>;
@@ -1180,8 +1178,8 @@ def err_omp_expected_identifier_for_critical : Error<
"expected identifier specifying the name of the 'omp critical' directive">;
def err_omp_expected_reduction_identifier : Error<
"expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&', or '||'">;
-def err_omp_decl_in_declare_simd : Error<
- "function declaration is expected after 'declare simd' directive">;
+def err_omp_decl_in_declare_simd_variant : Error<
+ "function declaration is expected after 'declare %select{simd|variant}0' directive">;
def err_omp_unknown_map_type : Error<
"incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'">;
def err_omp_unknown_map_type_modifier : Error<
@@ -1195,13 +1193,36 @@ def err_omp_declare_simd_inbranch_notinbranch : Error<
def err_expected_end_declare_target : Error<
"expected '#pragma omp end declare target'">;
def err_omp_declare_target_unexpected_clause: Error<
- "unexpected '%0' clause, only 'to' or 'link' clauses expected">;
+ "unexpected '%0' clause, only %select{'to' or 'link'|'to', 'link' or 'device_type'}1 clauses expected">;
def err_omp_expected_clause: Error<
"expected at least one clause on '#pragma omp %0' directive">;
def err_omp_mapper_illegal_identifier : Error<
"illegal OpenMP user-defined mapper identifier">;
def err_omp_mapper_expected_declarator : Error<
"expected declarator on 'omp declare mapper' directive">;
+def err_omp_declare_variant_wrong_clause : Error<
+ "expected '%0' clause on 'omp declare variant' directive">;
+def err_omp_declare_variant_no_ctx_selector : Error<
+ "expected context selector in '%0' clause on 'omp declare variant' directive">;
+def err_omp_declare_variant_equal_expected : Error<
+ "expected '=' after '%0' context selector set name on 'omp declare variant' directive">;
+def warn_omp_declare_variant_cs_name_expected : Warning<
+ "unknown context selector in '%0' context selector set of 'omp declare variant' directive, ignored">,
+ InGroup<OpenMPClauses>;
+def err_omp_declare_variant_item_expected : Error<
+ "expected %0 in '%1' context selector of '%2' selector set of 'omp declare variant' directive">;
+def err_omp_declare_variant_ctx_set_mutiple_use : Error<
+ "context selector set '%0' is used already in the same 'omp declare variant' directive">;
+def note_omp_declare_variant_ctx_set_used_here : Note<
+ "previously context selector set '%0' used here">;
+def err_omp_expected_comma_brace : Error<"expected '}' or ',' after '%0'">;
+def err_omp_declare_variant_ctx_mutiple_use : Error<
+ "context trait selector '%0' is used already in the same '%1' context selector set of 'omp declare variant' directive">;
+def note_omp_declare_variant_ctx_used_here : Note<
+ "previously context trait selector '%0' used here">;
+def warn_omp_more_one_device_type_clause : Warning<
+ "more than one 'device_type' clause is specified">,
+ InGroup<OpenMPClauses>;
// Pragma loop support.
def err_pragma_loop_missing_argument : Error<
@@ -1210,7 +1231,7 @@ def err_pragma_loop_missing_argument : Error<
def err_pragma_loop_invalid_option : Error<
"%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, "
"vectorize_width, interleave, interleave_count, unroll, unroll_count, "
- "pipeline, pipeline_initiation_interval, or distribute">;
+ "pipeline, pipeline_initiation_interval, vectorize_predicate, or distribute">;
def err_pragma_fp_invalid_option : Error<
"%select{invalid|missing}0 option%select{ %1|}0; expected contract">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index effcbad78b23..d802a92c42c0 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12,7 +12,6 @@
let Component = "Sema" in {
let CategoryName = "Semantic Issue" in {
-
def note_previous_decl : Note<"%0 declared here">;
def note_entity_declared_at : Note<"%0 declared here">;
def note_callee_decl : Note<"%0 declared here">;
@@ -155,7 +154,7 @@ def err_variably_modified_new_type : Error<
// C99 Designated Initializers
def ext_designated_init : Extension<
- "designated initializers are a C99 feature">, InGroup<C99>;
+ "designated initializers are a C99 feature">, InGroup<C99Designator>;
def err_array_designator_negative : Error<
"array designator value '%0' is negative">;
def err_array_designator_empty_range : Error<
@@ -174,15 +173,17 @@ def err_field_designator_nonfield : Error<
def note_field_designator_found : Note<"field designator refers here">;
def err_designator_for_scalar_init : Error<
"designator in initializer for scalar type %0">;
-def warn_subobject_initializer_overrides : Warning<
- "subobject initialization overrides initialization of other fields "
- "within its enclosing subobject">, InGroup<InitializerOverrides>;
def warn_initializer_overrides : Warning<
- "initializer overrides prior initialization of this subobject">,
- InGroup<InitializerOverrides>;
+ "initializer %select{partially |}0overrides prior initialization of "
+ "this subobject">, InGroup<InitializerOverrides>;
+def ext_initializer_overrides : ExtWarn<warn_initializer_overrides.Text>,
+ InGroup<InitializerOverrides>, SFINAEFailure;
+def err_initializer_overrides_destructed : Error<
+ "initializer would partially override prior initialization of object of "
+ "type %1 with non-trivial destruction">;
def note_previous_initializer : Note<
"previous initialization %select{|with side effects }0is here"
- "%select{| (side effects may not occur at run time)}0">;
+ "%select{| (side effects will not occur at run time)}0">;
def err_designator_into_flexible_array_member : Error<
"designator into flexible array member subobject">;
def note_flexible_array_member : Note<
@@ -190,6 +191,28 @@ def note_flexible_array_member : Note<
def ext_flexible_array_init : Extension<
"flexible array initialization is a GNU extension">, InGroup<GNUFlexibleArrayInitializer>;
+// C++20 designated initializers
+def ext_cxx_designated_init : Extension<
+ "designated initializers are a C++20 extension">, InGroup<CXX2aDesignator>;
+def warn_cxx17_compat_designated_init : Warning<
+ "designated initializers are incompatible with C++ standards before C++20">,
+ InGroup<CXXPre2aCompatPedantic>, DefaultIgnore;
+def ext_designated_init_mixed : ExtWarn<
+ "mixture of designated and non-designated initializers in the same "
+ "initializer list is a C99 extension">, InGroup<C99Designator>;
+def note_designated_init_mixed : Note<
+ "first non-designated initializer is here">;
+def ext_designated_init_array : ExtWarn<
+ "array designators are a C99 extension">, InGroup<C99Designator>;
+def ext_designated_init_nested : ExtWarn<
+ "nested designators are a C99 extension">, InGroup<C99Designator>;
+def ext_designated_init_reordered : ExtWarn<
+ "ISO C++ requires field designators to be specified in declaration order; "
+ "field %1 will be initialized after field %0">, InGroup<ReorderInitList>,
+ SFINAEFailure;
+def note_previous_field_init : Note<
+ "previous initialization for field %0 is here">;
+
// Declarations.
def ext_plain_complex : ExtWarn<
"plain '_Complex' requires a type specifier; assuming '_Complex double'">;
@@ -598,6 +621,10 @@ def ext_implicit_lib_function_decl : ExtWarn<
def note_include_header_or_declare : Note<
"include the header <%0> or explicitly provide a declaration for '%1'">;
def note_previous_builtin_declaration : Note<"%0 is a builtin with type %1">;
+def warn_implicit_decl_no_jmp_buf
+ : Warning<"declaration of built-in function '%0' requires the declaration"
+ " of the 'jmp_buf' type, commonly provided in the header <setjmp.h>.">,
+ InGroup<DiagGroup<"incomplete-setjmp-declaration">>;
def warn_implicit_decl_requires_sysheader : Warning<
"declaration of built-in function '%1' requires inclusion of the header <%0>">,
InGroup<BuiltinRequiresHeader>;
@@ -2212,6 +2239,11 @@ def err_class_marked_final_used_as_base : Error<
"base %0 is marked '%select{final|sealed}1'">;
def warn_abstract_final_class : Warning<
"abstract class is marked '%select{final|sealed}0'">, InGroup<AbstractFinalClass>;
+def warn_final_dtor_non_final_class : Warning<
+ "class with destructor marked '%select{final|sealed}0' cannot be inherited from">,
+ InGroup<FinalDtorNonFinalClass>;
+def note_final_dtor_non_final_class_silence : Note<
+ "mark %0 as '%select{final|sealed}1' to silence this warning">;
// C++11 attributes
def err_repeat_attribute : Error<"%0 attribute cannot be repeated">;
@@ -2326,18 +2358,24 @@ def warn_cxx14_compat_constexpr_not_const : Warning<
"in C++14; add 'const' to avoid a change in behavior">,
InGroup<DiagGroup<"constexpr-not-const">>;
def err_invalid_constexpr : Error<
- "%select{function parameter|typedef|non-static data member}0 "
- "cannot be %select{constexpr|consteval}1">;
+ "%select{function parameter|typedef}0 "
+ "cannot be %sub{select_constexpr_spec_kind}1">;
def err_invalid_constexpr_member : Error<"non-static data member cannot be "
"constexpr%select{; did you intend to make it %select{const|static}0?|}1">;
def err_constexpr_tag : Error<
"%select{class|struct|interface|union|enum}0 "
- "cannot be marked %select{constexpr|consteval}1">;
+ "cannot be marked %sub{select_constexpr_spec_kind}1">;
def err_constexpr_dtor : Error<
- "destructor cannot be marked %select{constexpr|consteval}0">;
+ "destructor cannot be declared %sub{select_constexpr_spec_kind}0">;
+def err_constexpr_dtor_subobject : Error<
+ "destructor cannot be declared %sub{select_constexpr_spec_kind}0 because "
+ "%select{data member %2|base class %3}1 does not have a "
+ "constexpr destructor">;
+def note_constexpr_dtor_subobject : Note<
+ "%select{data member %1|base class %2}0 declared here">;
def err_constexpr_wrong_decl_kind : Error<
- "%select{constexpr|consteval}0 can only be used "
- "in %select{variable and |}0function declarations">;
+ "%sub{select_constexpr_spec_kind}0 can only be used "
+ "in %select{|variable and function|function|variable}0 declarations">;
def err_invalid_constexpr_var_decl : Error<
"constexpr variable declaration must be a definition">;
def err_constexpr_static_mem_var_requires_init : Error<
@@ -2346,6 +2384,8 @@ 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_var_requires_const_destruction : Error<
+ "constexpr variable %0 must have constant destruction">;
def err_constexpr_redecl_mismatch : Error<
"%select{non-constexpr|constexpr|consteval}1 declaration of %0"
" follows %select{non-constexpr|constexpr|consteval}2 declaration">;
@@ -2406,9 +2446,13 @@ def err_constexpr_local_var_static : Error<
def err_constexpr_local_var_non_literal_type : Error<
"variable of non-literal type %1 cannot be defined in a constexpr "
"%select{function|constructor}0">;
-def err_constexpr_local_var_no_init : Error<
- "variables defined in a constexpr %select{function|constructor}0 must be "
- "initialized">;
+def ext_constexpr_local_var_no_init : ExtWarn<
+ "uninitialized variable in a constexpr %select{function|constructor}0 "
+ "is a C++20 extension">, InGroup<CXX2a>;
+def warn_cxx17_compat_constexpr_local_var_no_init : Warning<
+ "uninitialized variable in a constexpr %select{function|constructor}0 "
+ "is incompatible with C++ standards before C++20">,
+ InGroup<CXXPre2aCompat>, DefaultIgnore;
def ext_constexpr_function_never_constant_expr : ExtWarn<
"constexpr %select{function|constructor}0 never produces a "
"constant expression">, InGroup<DiagGroup<"invalid-constexpr">>, DefaultError;
@@ -2433,10 +2477,8 @@ def warn_cxx11_compat_constexpr_body_multiple_return : Warning<
InGroup<CXXPre14Compat>, DefaultIgnore;
def note_constexpr_body_previous_return : Note<
"previous return statement is here">;
-def err_constexpr_function_try_block : Error<
- "function try block not allowed in constexpr %select{function|constructor}0">;
-// c++2a function try blocks in constexpr
+// C++2a function try blocks in constexpr
def ext_constexpr_function_try_block_cxx2a : ExtWarn<
"function try block in constexpr %select{function|constructor}0 is "
"a C++2a extension">, InGroup<CXX2a>;
@@ -2445,10 +2487,20 @@ def warn_cxx17_compat_constexpr_function_try_block : Warning<
"incompatible with C++ standards before C++2a">,
InGroup<CXXPre2aCompat>, DefaultIgnore;
-def err_constexpr_union_ctor_no_init : Error<
- "constexpr union constructor does not initialize any member">;
-def err_constexpr_ctor_missing_init : Error<
- "constexpr constructor must initialize all members">;
+def ext_constexpr_union_ctor_no_init : ExtWarn<
+ "constexpr union constructor that does not initialize any member "
+ "is a C++20 extension">, InGroup<CXX2a>;
+def warn_cxx17_compat_constexpr_union_ctor_no_init : Warning<
+ "constexpr union constructor that does not initialize any member "
+ "is incompatible with C++ standards before C++20">,
+ InGroup<CXXPre2aCompat>, DefaultIgnore;
+def ext_constexpr_ctor_missing_init : ExtWarn<
+ "constexpr constructor that does not initialize all members "
+ "is a C++20 extension">, InGroup<CXX2a>;
+def warn_cxx17_compat_constexpr_ctor_missing_init : Warning<
+ "constexpr constructor that does not initialize all members "
+ "is incompatible with C++ standards before C++20">,
+ InGroup<CXXPre2aCompat>, DefaultIgnore;
def note_constexpr_ctor_missing_init : Note<
"member not initialized by constructor">;
def note_non_literal_no_constexpr_ctors : Note<
@@ -2463,6 +2515,8 @@ 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_non_constexpr_dtor : Note<
+ "%0 is not literal because its destructor is not constexpr">;
def note_non_literal_lambda : Note<
"lambda closure types are non-literal types before C++17">;
def warn_private_extern : Warning<
@@ -2472,8 +2526,6 @@ def note_private_extern : Note<
"use __attribute__((visibility(\"hidden\"))) attribute instead">;
// C++ Concepts
-def err_concept_initialized_with_non_bool_type : Error<
- "constraint expression must be of type 'bool' but is of type %0">;
def err_concept_decls_may_only_appear_in_global_namespace_scope : Error<
"concept declarations may only appear in global or namespace scope">;
def err_concept_no_parameters : Error<
@@ -2485,9 +2537,14 @@ def err_concept_no_associated_constraints : Error<
"concept cannot have associated constraints">;
def err_concept_not_implemented : Error<
"sorry, unimplemented concepts feature %0 used">;
+def err_non_constant_constraint_expression : Error<
+ "substitution into constraint expression resulted in a non-constant "
+ "expression">;
+def err_non_bool_atomic_constraint : Error<
+ "atomic constraint must be of type 'bool' (found %0)">;
-def err_template_different_associated_constraints : Error<
- "associated constraints differ in template redeclaration">;
+def err_template_different_requires_clause : Error<
+ "requires clause differs in template redeclaration">;
// C++11 char16_t/char32_t
def warn_cxx98_compat_unicode_type : Warning<
@@ -2519,6 +2576,9 @@ def err_nsobject_attribute : Error<
"'NSObject' attribute is for pointer types only">;
def err_attributes_are_not_compatible : Error<
"%0 and %1 attributes are not compatible">;
+def err_attribute_invalid_argument : Error<
+ "%select{'void'|a reference type|an array type|a non-vector or "
+ "non-vectorizable scalar type}0 is an invalid argument to attribute %1">;
def err_attribute_wrong_number_arguments : Error<
"%0 attribute %plural{0:takes no arguments|1:takes one argument|"
":requires exactly %1 arguments}1">;
@@ -2567,8 +2627,6 @@ def err_attribute_argument_out_of_range : Error<
def err_init_priority_object_attr : Error<
"can only use 'init_priority' attribute on file-scope definitions "
"of objects of class type">;
-def err_attribute_argument_vec_type_hint : Error<
- "invalid attribute argument %0 - expecting a vector or vectorizable scalar type">;
def err_attribute_argument_out_of_bounds : Error<
"%0 attribute parameter %1 is out of bounds">;
def err_attribute_only_once_per_parameter : Error<
@@ -2778,6 +2836,11 @@ def err_no_accessor_for_property : Error<
def err_cannot_find_suitable_accessor : Error<
"cannot find suitable %select{getter|setter}0 for property %1">;
+def warn_alloca : Warning<
+ "use of function %0 is discouraged; there is no way to check for failure but "
+ "failure may still occur, resulting in a possibly exploitable security vulnerability">,
+ InGroup<DiagGroup<"alloca">>, DefaultIgnore;
+
def warn_alloca_align_alignof : Warning<
"second argument to __builtin_alloca_with_align is supposed to be in bits">,
InGroup<DiagGroup<"alloca-with-align-alignof">>;
@@ -2793,6 +2856,10 @@ def err_alignment_dependent_typedef_name : Error<
def err_attribute_aligned_too_great : Error<
"requested alignment must be %0 bytes or smaller">;
+def warn_assume_aligned_too_great
+ : Warning<"requested alignment must be %0 bytes or smaller; maximum "
+ "alignment assumed">,
+ InGroup<DiagGroup<"builtin-assume-aligned-alignment">>;
def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
"%q0 redeclared without %1 attribute: previous %1 ignored">,
InGroup<MicrosoftInconsistentDllImport>;
@@ -2950,6 +3017,10 @@ def warn_gnu_inline_attribute_requires_inline : Warning<
"'gnu_inline' attribute requires function to be marked 'inline',"
" attribute ignored">,
InGroup<IgnoredAttributes>;
+def warn_gnu_inline_cplusplus_without_extern : Warning<
+ "'gnu_inline' attribute without 'extern' in C++ treated as externally"
+ " available, this changed in Clang 10">,
+ InGroup<DiagGroup<"gnu-inline-cpp-without-extern">>;
def err_attribute_vecreturn_only_vector_member : Error<
"the vecreturn attribute can only be used on a class or structure with one member, which must be a vector">;
def err_attribute_vecreturn_only_pod_record : Error<
@@ -2966,6 +3037,7 @@ def warn_cconv_unsupported : Warning<
"|on builtin function"
"}1">,
InGroup<IgnoredAttributes>;
+def error_cconv_unsupported : Error<warn_cconv_unsupported.Text>;
def err_cconv_knr : Error<
"function with no prototype cannot use the %0 calling convention">;
def warn_cconv_knr : Warning<
@@ -3251,9 +3323,9 @@ def warn_impcast_integer_precision_constant : Warning<
def warn_impcast_bitfield_precision_constant : Warning<
"implicit truncation from %2 to bit-field changes value from %0 to %1">,
InGroup<BitFieldConstantConversion>;
-def warn_impcast_constant_int_to_objc_bool : Warning<
- "implicit conversion from constant value %0 to BOOL; "
- "the only well defined values for BOOL are YES and NO">,
+def warn_impcast_constant_value_to_objc_bool : Warning<
+ "implicit conversion from constant value %0 to 'BOOL'; "
+ "the only well defined values for 'BOOL' are YES and NO">,
InGroup<ObjCBoolConstantConversion>;
def warn_impcast_fixed_point_range : Warning<
@@ -3269,6 +3341,20 @@ def warn_impcast_literal_float_to_integer_out_of_range : Warning<
def warn_impcast_float_integer : Warning<
"implicit conversion turns floating-point number into integer: %0 to %1">,
InGroup<FloatConversion>, DefaultIgnore;
+def warn_impcast_float_to_objc_signed_char_bool : Warning<
+ "implicit conversion from floating-point type %0 to 'BOOL'">,
+ InGroup<ObjCSignedCharBoolImplicitFloatConversion>;
+def warn_impcast_int_to_objc_signed_char_bool : Warning<
+ "implicit conversion from integral type %0 to 'BOOL'">,
+ InGroup<ObjCSignedCharBoolImplicitIntConversion>, DefaultIgnore;
+
+// Implicit int -> float conversion precision loss warnings.
+def warn_impcast_integer_float_precision : Warning<
+ "implicit conversion from %0 to %1 may lose precision">,
+ InGroup<ImplicitIntFloatConversion>, DefaultIgnore;
+def warn_impcast_integer_float_precision_constant : Warning<
+ "implicit conversion from %2 to %3 changes value from %0 to %1">,
+ InGroup<ImplicitIntFloatConversion>;
def warn_impcast_float_to_integer : Warning<
"implicit conversion from %0 to %1 changes value from %2 to %3">,
@@ -3292,6 +3378,10 @@ def warn_impcast_bool_to_null_pointer : Warning<
def warn_non_literal_null_pointer : Warning<
"expression which evaluates to zero treated as a null pointer constant of "
"type %0">, InGroup<NonLiteralNullConversion>;
+def warn_pointer_compare : Warning<
+ "comparing a pointer to a null character constant; did you mean "
+ "to compare to %select{NULL|(void *)0}0?">,
+ InGroup<DiagGroup<"pointer-compare">>;
def warn_impcast_null_pointer_to_integer : Warning<
"implicit conversion of %select{NULL|nullptr}0 constant to %1">,
InGroup<NullConversion>;
@@ -3318,6 +3408,18 @@ def warn_address_of_reference_bool_conversion : Warning<
"code; pointer may be assumed to always convert to true">,
InGroup<UndefinedBoolConversion>;
+def warn_xor_used_as_pow : Warning<
+ "result of '%0' is %1; did you mean exponentiation?">,
+ InGroup<XorUsedAsPow>;
+def warn_xor_used_as_pow_base_extra : Warning<
+ "result of '%0' is %1; did you mean '%2' (%3)?">,
+ InGroup<XorUsedAsPow>;
+def warn_xor_used_as_pow_base : Warning<
+ "result of '%0' is %1; did you mean '%2'?">,
+ InGroup<XorUsedAsPow>;
+def note_xor_used_as_pow_silence : Note<
+ "replace expression with '%0' %select{|or use 'xor' instead of '^' }1to silence this warning">;
+
def warn_null_pointer_compare : Warning<
"comparison of %select{address of|function|array}0 '%1' %select{not |}2"
"equal to a null pointer is always %select{true|false}2">,
@@ -3338,9 +3440,15 @@ def warn_address_of_reference_null_compare : Warning<
InGroup<TautologicalUndefinedCompare>;
def note_reference_is_return_value : Note<"%0 returns a reference">;
+def note_pointer_declared_here : Note<
+ "pointer %0 declared here">;
def warn_division_sizeof_ptr : Warning<
"'%0' will return the size of the pointer, not the array itself">,
InGroup<DiagGroup<"sizeof-pointer-div">>;
+def warn_division_sizeof_array : Warning<
+ "expression does not compute the number of elements in this array; element "
+ "type is %0, not %1">,
+ InGroup<DiagGroup<"sizeof-array-div">>;
def note_function_warning_silence : Note<
"prefix with the address-of operator to silence this warning">;
@@ -3661,7 +3769,8 @@ def note_ovl_too_many_candidates : Note<
"pass -fshow-overloads=all to show them">;
def select_ovl_candidate_kind : TextSubstitution<
- "%select{function|function|constructor|"
+ "%select{function|function|function (with reversed parameter order)|"
+ "constructor|"
"constructor (the implicit default constructor)|"
"constructor (the implicit copy constructor)|"
"constructor (the implicit move constructor)|"
@@ -3855,10 +3964,7 @@ def note_implicit_member_target_infer_collision : Note<
def note_ambiguous_type_conversion: Note<
"because of ambiguity in conversion %diff{of $ to $|between types}0,1">;
-def note_ovl_builtin_binary_candidate : Note<
- "built-in candidate %0">;
-def note_ovl_builtin_unary_candidate : Note<
- "built-in candidate %0">;
+def note_ovl_builtin_candidate : Note<"built-in candidate %0">;
def err_ovl_no_viable_function_in_init : Error<
"no matching constructor for initialization of %0">;
def err_ovl_no_conversion_in_cast : Error<
@@ -3885,6 +3991,13 @@ def err_ovl_ambiguous_oper_unary : Error<
"use of overloaded operator '%0' is ambiguous (operand type %1)">;
def err_ovl_ambiguous_oper_binary : Error<
"use of overloaded operator '%0' is ambiguous (with operand types %1 and %2)">;
+def ext_ovl_ambiguous_oper_binary_reversed : ExtWarn<
+ "ISO C++20 considers use of overloaded operator '%0' (with operand types %1 "
+ "and %2) to be ambiguous despite there being a unique best viable function">,
+ InGroup<DiagGroup<"ambiguous-reversed-operator">>, SFINAEFailure;
+def note_ovl_ambiguous_oper_binary_reversed_candidate : Note<
+ "ambiguity is between a regular call to this operator and a call with the "
+ "argument order reversed">;
def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">;
def note_assign_lhs_incomplete : Note<"type %0 is incomplete">;
def err_ovl_deleted_oper : Error<
@@ -3892,6 +4005,9 @@ def err_ovl_deleted_oper : Error<
def err_ovl_deleted_special_oper : Error<
"object of type %0 cannot be %select{constructed|copied|moved|assigned|"
"assigned|destroyed}1 because its %sub{select_special_member_kind}1 is implicitly deleted">;
+def err_ovl_rewrite_equalequal_not_bool : Error<
+ "return type %0 of selected 'operator==' function for rewritten "
+ "'%1' comparison is not 'bool'">;
def err_ovl_no_viable_subscript :
Error<"no viable overloaded operator[] for type %0">;
def err_ovl_no_oper :
@@ -3934,6 +4050,8 @@ def err_ovl_no_viable_literal_operator : Error<
// C++ Template Declarations
def err_template_param_shadow : Error<
"declaration of %0 shadows template parameter">;
+def ext_template_param_shadow : ExtWarn<
+ err_template_param_shadow.Text>, InGroup<MicrosoftTemplate>;
def note_template_param_here : Note<"template parameter is declared here">;
def warn_template_export_unsupported : Warning<
"exported templates are unsupported">;
@@ -4392,6 +4510,10 @@ def note_prior_template_arg_substitution : Note<
" template parameter%1 %2">;
def note_template_default_arg_checking : Note<
"while checking a default template argument used here">;
+def note_concept_specialization_here : Note<
+ "while checking the satisfaction of concept '%0' requested here">;
+def note_constraint_substitution_here : Note<
+ "while substituting template arguments into constraint expression here">;
def note_instantiation_contexts_suppressed : Note<
"(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to "
"see all)">;
@@ -5334,9 +5456,6 @@ def err_arc_mismatched_cast : Error<
" 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_tag : Error<
- "ARC forbids %select{Objective-C objects|blocks}0 in "
- "%select{struct|interface|union|<<ERROR>>|enum}1">;
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">;
@@ -5626,9 +5745,18 @@ def note_precedence_silence : Note<
def warn_precedence_conditional : Warning<
"operator '?:' has lower precedence than '%0'; '%0' will be evaluated first">,
InGroup<Parentheses>;
+def warn_precedence_bitwise_conditional : Warning<
+ "operator '?:' has lower precedence than '%0'; '%0' will be evaluated first">,
+ InGroup<BitwiseConditionalParentheses>;
def note_precedence_conditional_first : Note<
"place parentheses around the '?:' expression to evaluate it first">;
+def warn_enum_constant_in_bool_context : Warning<
+ "converting the enum constant to a boolean">,
+ InGroup<IntInBoolContext>, DefaultIgnore;
+def warn_left_shift_in_bool_context : Warning<
+ "converting the result of '<<' to a boolean; did you mean '(%0) != 0'?">,
+ InGroup<IntInBoolContext>, DefaultIgnore;
def warn_logical_instead_of_bitwise : Warning<
"use of logical '%0' with constant operand">,
InGroup<DiagGroup<"constant-logical-operand">>;
@@ -5638,10 +5766,10 @@ def note_logical_instead_of_bitwise_remove_constant : Note<
"remove constant to silence this warning">;
def warn_bitwise_op_in_bitwise_op : Warning<
- "'%0' within '%1'">, InGroup<BitwiseOpParentheses>;
+ "'%0' within '%1'">, InGroup<BitwiseOpParentheses>, DefaultIgnore;
def warn_logical_and_in_logical_or : Warning<
- "'&&' within '||'">, InGroup<LogicalOpParentheses>;
+ "'&&' within '||'">, InGroup<LogicalOpParentheses>, DefaultIgnore;
def warn_overloaded_shift_in_comparison :Warning<
"overloaded operator %select{>>|<<}0 has higher precedence than "
@@ -5718,6 +5846,9 @@ def err_arithmetic_nonfragile_interface : Error<
"arithmetic on pointer to interface %0, which is not a constant size for "
"this architecture and platform">;
+def warn_deprecated_comma_subscript : Warning<
+ "top-level comma expression in array subscript is deprecated">,
+ InGroup<DeprecatedCommaSubscript>;
def ext_subscript_non_lvalue : Extension<
"ISO C90 does not allow subscripting non-lvalue array">;
@@ -6038,8 +6169,8 @@ def warn_tautological_constant_compare : Warning<
"%select{%1|%3}0 is always %4">,
InGroup<TautologicalTypeLimitCompare>, DefaultIgnore;
def warn_tautological_compare_objc_bool : Warning<
- "result of comparison of constant %0 with expression of type BOOL"
- " is always %1, as the only well defined values for BOOL are YES and NO">,
+ "result of comparison of constant %0 with expression of type 'BOOL'"
+ " is always %1, as the only well defined values for 'BOOL' are YES and NO">,
InGroup<TautologicalObjCBoolCompare>;
def warn_mixed_sign_comparison : Warning<
@@ -6051,10 +6182,22 @@ def warn_out_of_range_compare : Warning<
InGroup<TautologicalOutOfRangeCompare>;
def warn_tautological_bool_compare : Warning<warn_out_of_range_compare.Text>,
InGroup<TautologicalConstantCompare>;
+def warn_integer_constants_in_conditional_always_true : Warning<
+ "converting the result of '?:' with integer constants to a boolean always "
+ "evaluates to 'true'">,
+ InGroup<TautologicalConstantCompare>;
+def warn_left_shift_always : Warning<
+ "converting the result of '<<' to a boolean always evaluates "
+ "to %select{false|true}0">,
+ InGroup<TautologicalConstantCompare>;
def warn_comparison_of_mixed_enum_types : Warning<
"comparison of two values with different enumeration types"
"%diff{ ($ and $)|}0,1">,
InGroup<EnumCompare>;
+def warn_conditional_mixed_enum_types : Warning<
+ "enumeration type mismatch in conditional expression"
+ "%diff{ ($ and $)|}0,1">,
+ InGroup<EnumCompareConditional>, DefaultIgnore;
def warn_comparison_of_mixed_enum_types_switch : Warning<
"comparison of two values with different enumeration types in switch statement"
"%diff{ ($ and $)|}0,1">,
@@ -6093,6 +6236,8 @@ def err_invalid_qualified_function_type : Error<
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_qualified_function_typeid : Error<
+ "type operand %0 of 'typeid' cannot have '%1' qualifier">;
def err_ref_qualifier_overload : Error<
"cannot overload a member function %select{without a ref-qualifier|with "
@@ -6517,6 +6662,10 @@ def note_member_declared_here : Note<
"member %0 declared here">;
def note_member_first_declared_here : Note<
"member %0 first declared here">;
+def warn_bitwise_negation_bool : Warning<
+ "bitwise negation of a boolean expression%select{;| always evaluates to 'true';}0 "
+ "did you mean logical negation?">,
+ InGroup<DiagGroup<"bool-operation">>;
def err_decrement_bool : Error<"cannot decrement expression of type bool">;
def warn_increment_bool : Warning<
"incrementing expression of type bool is deprecated and "
@@ -6526,6 +6675,26 @@ def ext_increment_bool : ExtWarn<
DefaultError, InGroup<IncrementBool>;
def err_increment_decrement_enum : Error<
"cannot %select{decrement|increment}0 expression of enum type %1">;
+
+def warn_deprecated_increment_decrement_volatile : Warning<
+ "%select{decrement|increment}0 of object of volatile-qualified type %1 "
+ "is deprecated">, InGroup<DeprecatedVolatile>;
+def warn_deprecated_simple_assign_volatile : Warning<
+ "use of result of assignment to object of volatile-qualified type %0 "
+ "is deprecated">, InGroup<DeprecatedVolatile>;
+def warn_deprecated_compound_assign_volatile : Warning<
+ "compound assignment to object of volatile-qualified type %0 is deprecated">,
+ InGroup<DeprecatedVolatile>;
+def warn_deprecated_volatile_return : Warning<
+ "volatile-qualified return type %0 is deprecated">,
+ InGroup<DeprecatedVolatile>;
+def warn_deprecated_volatile_param : Warning<
+ "volatile-qualified parameter type %0 is deprecated">,
+ InGroup<DeprecatedVolatile>;
+def warn_deprecated_volatile_structured_binding : Warning<
+ "volatile qualifier in structured binding declaration is deprecated">,
+ InGroup<DeprecatedVolatile>;
+
def err_catch_incomplete_ptr : Error<
"cannot catch pointer to incomplete type %0">;
def err_catch_incomplete_ref : Error<
@@ -7426,6 +7595,12 @@ def warn_unused_container_subscript_expr : Warning<
def warn_unused_call : Warning<
"ignoring return value of function declared with %0 attribute">,
InGroup<UnusedValue>;
+def warn_unused_constructor : Warning<
+ "ignoring temporary created by a constructor declared with %0 attribute">,
+ InGroup<UnusedValue>;
+def warn_unused_constructor_msg : Warning<
+ "ignoring temporary created by a constructor declared with %0 attribute: %1">,
+ InGroup<UnusedValue>;
def warn_side_effects_unevaluated_context : Warning<
"expression with side effects has no effect in an unevaluated context">,
InGroup<UnevaluatedExpression>;
@@ -7435,6 +7610,9 @@ def warn_side_effects_typeid : Warning<
def warn_unused_result : Warning<
"ignoring return value of function declared with %0 attribute">,
InGroup<UnusedResult>;
+def warn_unused_result_msg : Warning<
+ "ignoring return value of function declared with %0 attribute: %1">,
+ InGroup<UnusedResult>;
def warn_unused_volatile : Warning<
"expression result unused; assign into a variable to force a volatile load">,
InGroup<DiagGroup<"unused-volatile-lvalue">>;
@@ -7443,6 +7621,8 @@ def ext_cxx14_attr : Extension<
"use of the %0 attribute is a C++14 extension">, InGroup<CXX14>;
def ext_cxx17_attr : Extension<
"use of the %0 attribute is a C++17 extension">, InGroup<CXX17>;
+def ext_cxx2a_attr : Extension<
+ "use of the %0 attribute is a C++2a extension">, InGroup<CXX2a>;
def warn_unused_comparison : Warning<
"%select{equality|inequality|relational|three-way}0 comparison result unused">,
@@ -7453,10 +7633,30 @@ 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">;
+// C++20 constinit and require_constant_initialization attribute
+def warn_cxx20_compat_constinit : Warning<
+ "'constinit' specifier is incompatible with C++ standards before C++20">,
+ InGroup<CXX2aCompat>, DefaultIgnore;
+def err_constinit_local_variable : Error<
+ "local variable cannot be declared 'constinit'">;
def err_require_constant_init_failed : Error<
"variable does not have a constant initializer">;
def note_declared_required_constant_init_here : Note<
- "required by 'require_constant_initialization' attribute here">;
+ "required by %select{'require_constant_initialization' attribute|"
+ "'constinit' specifier}0 here">;
+def ext_constinit_missing : ExtWarn<
+ "'constinit' specifier missing on initializing declaration of %0">,
+ InGroup<DiagGroup<"missing-constinit">>;
+def note_constinit_specified_here : Note<"variable declared constinit here">;
+def err_constinit_added_too_late : Error<
+ "'constinit' specifier added after initialization of variable">;
+def warn_require_const_init_added_too_late : Warning<
+ "'require_constant_initialization' attribute added after initialization "
+ "of variable">, InGroup<IgnoredAttributes>;
+def note_constinit_missing_here : Note<
+ "add the "
+ "%select{'require_constant_initialization' attribute|'constinit' specifier}0 "
+ "to the initializing declaration here">;
def err_dimension_expr_not_constant_integer : Error<
"dimension expression does not evaluate to a constant unsigned int">;
@@ -7493,8 +7693,6 @@ let CategoryName = "Inline Assembly Issue" in {
"invalid lvalue in asm input for constraint '%0'">;
def err_asm_invalid_input_constraint : Error<
"invalid input constraint '%0' in asm">;
- def err_asm_immediate_expected : Error<"constraint '%0' expects "
- "an integer constant expression">;
def err_asm_tying_incompatible_types : Error<
"unsupported inline asm: input with type "
"%diff{$ matching output with type $|}0,1">;
@@ -7583,7 +7781,7 @@ def err_mem_init_not_member_or_class : Error<
def warn_initializer_out_of_order : Warning<
"%select{field|base class}0 %1 will be initialized after "
"%select{field|base}2 %3">,
- InGroup<Reorder>, DefaultIgnore;
+ InGroup<ReorderCtor>, DefaultIgnore;
def warn_abstract_vbase_init_ignored : Warning<
"initializer for virtual base class %0 of abstract class %1 "
"will never be used">,
@@ -7919,7 +8117,7 @@ def warn_array_index_precedes_bounds : Warning<
def warn_array_index_exceeds_bounds : Warning<
"array index %0 is past the end of the array (which contains %1 "
"element%s2)">, InGroup<ArrayBounds>;
-def note_array_index_out_of_bounds : Note<
+def note_array_declared_here : Note<
"array %0 declared here">;
def warn_printf_insufficient_data_args : Warning<
@@ -7940,16 +8138,17 @@ def warn_format_conversion_argument_type_mismatch : Warning<
"%select{type|underlying type}2 %1">,
InGroup<Format>;
def warn_format_conversion_argument_type_mismatch_pedantic : Extension<
- "format specifies type %0 but the argument has "
- "%select{type|underlying type}2 %1">,
+ warn_format_conversion_argument_type_mismatch.Text>,
InGroup<FormatPedantic>;
+def warn_format_conversion_argument_type_mismatch_confusion : Warning<
+ warn_format_conversion_argument_type_mismatch.Text>,
+ InGroup<FormatTypeConfusion>, DefaultIgnore;
def warn_format_argument_needs_cast : Warning<
"%select{values of type|enum values with underlying type}2 '%0' should not "
"be used as format arguments; add an explicit cast to %1 instead">,
InGroup<Format>;
def warn_format_argument_needs_cast_pedantic : Warning<
- "%select{values of type|enum values with underlying type}2 '%0' should not "
- "be used as format arguments; add an explicit cast to %1 instead">,
+ warn_format_argument_needs_cast.Text>,
InGroup<FormatPedantic>, DefaultIgnore;
def warn_printf_positional_arg_exceeds_data_args : Warning <
"data argument position '%0' exceeds the number of data arguments (%1)">,
@@ -8023,6 +8222,9 @@ def warn_printf_invalid_objc_flag: Warning<
def warn_scanf_scanlist_incomplete : Warning<
"no closing ']' for '%%[' in scanf format string">,
InGroup<Format>;
+def warn_format_bool_as_character : Warning<
+ "using '%0' format specifier, but argument has boolean value">,
+ InGroup<Format>;
def note_format_string_defined : Note<"format string is defined here">;
def note_format_fix_specifier : Note<"did you mean to use '%0'?">;
def note_printf_c_str: Note<"did you mean to call the %0 method?">;
@@ -8085,6 +8287,10 @@ def warn_dangling_member : Warning<
"%select{binds to|is}2 a temporary object "
"whose lifetime is shorter than the lifetime of the constructed object">,
InGroup<DanglingField>;
+def warn_dangling_lifetime_pointer_member : Warning<
+ "initializing pointer member %0 to point to a temporary object "
+ "whose lifetime is shorter than the lifetime of the constructed object">,
+ InGroup<DanglingGsl>;
def note_lifetime_extending_member_declared_here : Note<
"%select{%select{reference|'std::initializer_list'}0 member|"
"member with %select{reference|'std::initializer_list'}0 subobject}1 "
@@ -8103,6 +8309,10 @@ def warn_new_dangling_reference : Warning<
"temporary bound to reference member of allocated object "
"will be destroyed at the end of the full-expression">,
InGroup<DanglingField>;
+def warn_dangling_lifetime_pointer : Warning<
+ "object backing the pointer "
+ "will be destroyed at the end of the full-expression">,
+ InGroup<DanglingGsl>;
def warn_new_dangling_initializer_list : Warning<
"array backing "
"%select{initializer list subobject of the allocated object|"
@@ -8120,11 +8330,15 @@ def warn_unsupported_lifetime_extension : Warning<
// should result in a warning, since these always evaluate to a constant.
// Array comparisons have similar warnings
def warn_comparison_always : Warning<
- "%select{self-|array }0comparison always evaluates to %select{a constant|%2}1">,
+ "%select{self-|array }0comparison always evaluates to "
+ "%select{a constant|true|false|'std::strong_ordering::equal'}1">,
InGroup<TautologicalCompare>;
def warn_comparison_bitwise_always : Warning<
"bitwise comparison always evaluates to %select{false|true}0">,
- InGroup<TautologicalCompare>;
+ InGroup<TautologicalBitwiseCompare>, DefaultIgnore;
+def warn_comparison_bitwise_or : Warning<
+ "bitwise or with non-zero value always evaluates to true">,
+ InGroup<TautologicalBitwiseCompare>, DefaultIgnore;
def warn_tautological_overlap_comparison : Warning<
"overlapping comparisons always evaluate to %select{false|true}0">,
InGroup<TautologicalOverlapCompare>, DefaultIgnore;
@@ -8503,10 +8717,11 @@ def warn_sync_fetch_and_nand_semantics_change : Warning<
InGroup<DiagGroup<"sync-fetch-and-nand-semantics-changed">>;
// Type
-def ext_invalid_sign_spec : Extension<"'%0' cannot be signed or unsigned">;
+def ext_wchar_t_sign_spec : ExtWarn<"'%0' cannot be signed or unsigned">,
+ InGroup<DiagGroup<"signed-unsigned-wchar">>, DefaultError;
def warn_receiver_forward_class : Warning<
- "receiver %0 is a forward class and corresponding @interface may not exist">,
- InGroup<ForwardClassReceiver>;
+ "receiver %0 is a forward class and corresponding @interface may not exist">,
+ InGroup<ForwardClassReceiver>;
def note_method_sent_forward_class : Note<"method %0 is used for the forward class">;
def ext_missing_declspec : ExtWarn<
"declaration specifier missing, defaulting to 'int'">;
@@ -8984,7 +9199,7 @@ def ext_omp_loop_not_canonical_init : ExtWarn<
"('var = init' or 'T var = init')">, InGroup<OpenMPLoopForm>;
def err_omp_loop_not_canonical_cond : Error<
"condition of OpenMP for loop must be a relational comparison "
- "('<', '<=', '>', or '>=') of loop variable %0">;
+ "('<', '<=', '>', %select{or '>='|'>=', or '!='}0) of loop variable %1">;
def err_omp_loop_not_canonical_incr : Error<
"increment clause of OpenMP for loop must perform simple addition "
"or subtraction on loop variable %0">;
@@ -9101,10 +9316,10 @@ def err_omp_single_copyprivate_with_nowait : Error<
"the 'copyprivate' clause must not be used with the 'nowait' clause">;
def note_omp_nowait_clause_here : Note<
"'nowait' clause is here">;
-def err_omp_single_decl_in_declare_simd : Error<
- "single declaration is expected after 'declare simd' directive">;
+def err_omp_single_decl_in_declare_simd_variant : Error<
+ "single declaration is expected after 'declare %select{simd|variant}0' directive">;
def err_omp_function_expected : Error<
- "'#pragma omp declare simd' can only be applied to functions">;
+ "'#pragma omp declare %select{simd|variant}0' can only be applied to functions">;
def err_omp_wrong_cancel_region : Error<
"one of 'for', 'parallel', 'sections' or 'taskgroup' is expected">;
def err_omp_parent_cancel_region_nowait : Error<
@@ -9286,6 +9501,44 @@ def err_omp_wrong_dependency_iterator_type : Error<
"expected an integer or a pointer type of the outer loop counter '%0' for non-rectangular nests">;
def err_omp_unsupported_type : Error <
"host requires %0 bit size %1 type support, but device '%2' does not support it">;
+def err_omp_lambda_capture_in_declare_target_not_to : Error<
+ "variable captured in declare target region must appear in a to clause">;
+def err_omp_device_type_mismatch : Error<
+ "'device_type(%0)' does not match previously specified 'device_type(%1)' for the same declaration">;
+def err_omp_wrong_device_function_call : Error<
+ "function with 'device_type(%0)' is not available on %select{device|host}1">;
+def note_omp_marked_device_type_here : Note<"marked as 'device_type(%0)' here">;
+def warn_omp_declare_target_after_first_use : Warning<
+ "declaration marked as declare target after first use, it may lead to incorrect results">,
+ InGroup<OpenMPTarget>;
+def err_omp_declare_variant_incompat_attributes : Error<
+ "'#pragma omp declare variant' is not compatible with any target-specific attributes">;
+def warn_omp_declare_variant_after_used : Warning<
+ "'#pragma omp declare variant' cannot be applied for function after first "
+ "usage; the original function might be used">, InGroup<SourceUsesOpenMP>;
+def warn_omp_declare_variant_after_emitted : Warning<
+ "'#pragma omp declare variant' cannot be applied to the function that was defined already;"
+ " the original function might be used">, InGroup<SourceUsesOpenMP>;
+def err_omp_declare_variant_noproto : Error<
+ "function with '#pragma omp declare variant' must have a prototype">;
+def note_omp_declare_variant_specified_here : Note<
+ "'#pragma omp declare variant' for function specified here">;
+def err_omp_declare_variant_doesnt_support : Error<
+ "'#pragma omp declare variant' does not "
+ "support %select{function templates|virtual functions|"
+ "deduced return types|constructors|destructors|deleted functions|"
+ "defaulted functions|constexpr functions|consteval function}0">;
+def err_omp_declare_variant_diff : Error<
+ "function with '#pragma omp declare variant' has a different %select{calling convention"
+ "|return type|constexpr specification|inline specification|storage class|"
+ "linkage}0">;
+def err_omp_declare_variant_incompat_types : Error<
+ "variant in '#pragma omp declare variant' with type %0 is incompatible with type %1"
+ >;
+def warn_omp_declare_variant_marked_as_declare_variant : Warning<
+ "variant function in '#pragma omp declare variant' is itself marked as '#pragma omp declare variant'"
+ >, InGroup<SourceUsesOpenMP>;
+def note_omp_marked_declare_variant_here : Note<"marked as 'declare variant' here">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
@@ -9725,6 +9978,8 @@ def err_std_compare_type_not_supported : Error<
"member '%2' is missing|"
"the type is not trivially copyable|"
"the type does not have the expected form}1">;
+def note_rewriting_operator_as_spaceship : Note<
+ "while rewriting comparison as call to 'operator<=>' declared here">;
// Memory Tagging Extensions (MTE) diagnostics
def err_memtag_arg_null_or_pointer : Error<
@@ -9735,8 +9990,6 @@ def err_memtag_arg_must_be_pointer : Error<
"%0 argument of MTE builtin function must be a pointer (%1 invalid)">;
def err_memtag_arg_must_be_integer : Error<
"%0 argument of MTE builtin function must be an integer type (%1 invalid)">;
-def err_memtag_arg_must_be_unsigned : Error<
- "%0 argument of MTE builtin function must be an unsigned integer type (%1 invalid)">;
def warn_dereference_of_noderef_type : Warning<
"dereferencing %0; was declared with a 'noderef' type">, InGroup<NoDeref>;
@@ -9751,6 +10004,11 @@ def err_builtin_launder_invalid_arg : Error<
"%select{non-pointer|function pointer|void pointer}0 argument to "
"'__builtin_launder' is not allowed">;
+def err_preserve_field_info_not_field : Error<
+ "__builtin_preserve_field_info argument %0 not a field access">;
+def err_preserve_field_info_not_const: Error<
+ "__builtin_preserve_field_info argument %0 not a constant">;
+
def err_bit_cast_non_trivially_copyable : Error<
"__builtin_bit_cast %select{source|destination}0 type must be trivially copyable">;
def err_bit_cast_type_size_mismatch : Error<
diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td
index 43ba19b5853e..757dbbeee3cc 100644
--- a/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -18,13 +18,16 @@ def err_fe_pch_malformed : Error<
def err_fe_pch_malformed_block : Error<
"malformed block record in PCH file: '%0'">, DefaultFatal;
def err_fe_pch_file_modified : Error<
- "file '%0' has been modified since the precompiled header '%1' was built">,
+ "file '%0' has been modified since the precompiled header '%1' was built"
+ ": %select{size|mtime|content}2 changed">,
DefaultFatal;
def err_fe_module_file_modified : Error<
- "file '%0' has been modified since the module file '%1' was built">,
+ "file '%0' has been modified since the module file '%1' was built"
+ ": %select{size|mtime|content}2 changed">,
DefaultFatal;
def err_fe_ast_file_modified : Error<
- "file '%0' has been modified since the AST file '%1' was built">,
+ "file '%0' has been modified since the AST file '%1' was built"
+ ": %select{size|mtime|content}2 changed">,
DefaultFatal;
def err_fe_pch_file_overridden : Error<
"file '%0' from the precompiled header has been overridden">;
@@ -77,13 +80,13 @@ def remark_module_import : Remark<
InGroup<ModuleImport>;
def err_imported_module_not_found : Error<
- "module '%0' in AST file '%1' (imported by AST file '%2') "
+ "module '%0' in AST file '%1' %select{(imported by AST file '%2') |}4"
"is not defined in any loaded module map file; "
"maybe you need to load '%3'?">, DefaultFatal;
def note_imported_by_pch_module_not_found : Note<
"consider adding '%0' to the header search path">;
def err_imported_module_modmap_changed : Error<
- "module '%0' imported by AST file '%1' found in a different module map file"
+ "module '%0' %select{in|imported by}4 AST file '%1' found in a different module map file"
" (%2) than when the importing AST file was built (%3)">, DefaultFatal;
def err_imported_module_relocated : Error<
"module '%0' was built in directory '%1' but now resides in "
@@ -399,6 +402,8 @@ def warn_module_uses_date_time : Warning<
def err_module_no_size_mtime_for_header : Error<
"cannot emit module %0: %select{size|mtime}1 must be explicitly specified "
"for missing header file \"%2\"">;
+def err_module_unable_to_hash_content : Error<
+ "failed to hash content for '%0' because memory buffer cannot be retrieved">;
} // let CategoryName
} // let Component
diff --git a/include/clang/Basic/Features.def b/include/clang/Basic/Features.def
index 7081c02e83ea..28eb694ba9a8 100644
--- a/include/clang/Basic/Features.def
+++ b/include/clang/Basic/Features.def
@@ -39,6 +39,8 @@
FEATURE(address_sanitizer,
LangOpts.Sanitize.hasOneOf(SanitizerKind::Address |
SanitizerKind::KernelAddress))
+FEATURE(leak_sanitizer,
+ LangOpts.Sanitize.has(SanitizerKind::Leak))
FEATURE(hwaddress_sanitizer,
LangOpts.Sanitize.hasOneOf(SanitizerKind::HWAddress |
SanitizerKind::KernelHWAddress))
@@ -187,7 +189,7 @@ FEATURE(cxx_variable_templates, LangOpts.CPlusPlus14)
// FEATURE(raw_invocation_type, LangOpts.CPlusPlus)
// Type traits
// N.B. Additional type traits should not be added to the following list.
-// Instead, they should be detected by has_extension.
+// Instead, they should be detected by has_builtin.
FEATURE(has_nothrow_assign, LangOpts.CPlusPlus)
FEATURE(has_nothrow_copy, LangOpts.CPlusPlus)
FEATURE(has_nothrow_constructor, LangOpts.CPlusPlus)
diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h
index 96983475f454..28cd05818087 100644
--- a/include/clang/Basic/FileManager.h
+++ b/include/clang/Basic/FileManager.h
@@ -45,12 +45,31 @@ class FileSystemStatCache;
class DirectoryEntry {
friend class FileManager;
+ // FIXME: We should not be storing a directory entry name here.
StringRef Name; // Name of the directory.
public:
StringRef getName() const { return Name; }
};
+/// A reference to a \c DirectoryEntry that includes the name of the directory
+/// as it was accessed by the FileManager's client.
+class DirectoryEntryRef {
+public:
+ const DirectoryEntry &getDirEntry() const { return *Entry->getValue(); }
+
+ StringRef getName() const { return Entry->getKey(); }
+
+private:
+ friend class FileManager;
+
+ DirectoryEntryRef(
+ llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>> *Entry)
+ : Entry(Entry) {}
+
+ const llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>> *Entry;
+};
+
/// Cached information about one file (either on disk
/// or in the virtual file system).
///
@@ -64,8 +83,8 @@ class FileEntry {
off_t Size; // File size in bytes.
time_t ModTime; // Modification time of file.
const DirectoryEntry *Dir; // Directory file lives in.
- unsigned UID; // A unique (small) ID for the file.
llvm::sys::fs::UniqueID UniqueID;
+ unsigned UID; // A unique (small) ID for the file.
bool IsNamedPipe;
bool IsValid; // Is this \c FileEntry initialized and valid?
@@ -106,6 +125,42 @@ public:
bool isOpenForTests() const { return File != nullptr; }
};
+/// A reference to a \c FileEntry that includes the name of the file as it was
+/// accessed by the FileManager's client.
+class FileEntryRef {
+public:
+ FileEntryRef() = delete;
+ FileEntryRef(StringRef Name, const FileEntry &Entry)
+ : Name(Name), Entry(&Entry) {}
+
+ const StringRef getName() const { return Name; }
+
+ bool isValid() const { return Entry->isValid(); }
+
+ const FileEntry &getFileEntry() const { return *Entry; }
+
+ off_t getSize() const { return Entry->getSize(); }
+
+ unsigned getUID() const { return Entry->getUID(); }
+
+ const llvm::sys::fs::UniqueID &getUniqueID() const {
+ return Entry->getUniqueID();
+ }
+
+ time_t getModificationTime() const { return Entry->getModificationTime(); }
+
+ friend bool operator==(const FileEntryRef &LHS, const FileEntryRef &RHS) {
+ return LHS.Entry == RHS.Entry && LHS.Name == RHS.Name;
+ }
+ friend bool operator!=(const FileEntryRef &LHS, const FileEntryRef &RHS) {
+ return !(LHS == RHS);
+ }
+
+private:
+ StringRef Name;
+ const FileEntry *Entry;
+};
+
/// Implements support for file system lookup, file system caching,
/// and directory search management.
///
@@ -131,21 +186,41 @@ class FileManager : public RefCountedBase<FileManager> {
/// The virtual files that we have allocated.
SmallVector<std::unique_ptr<FileEntry>, 4> VirtualFileEntries;
+ /// A set of files that bypass the maps and uniquing. They can have
+ /// conflicting filenames.
+ SmallVector<std::unique_ptr<FileEntry>, 0> BypassFileEntries;
+
/// A cache that maps paths to directory entries (either real or
- /// virtual) we have looked up
+ /// virtual) we have looked up, or an error that occurred when we looked up
+ /// the directory.
///
/// The actual Entries for real directories/files are
/// owned by UniqueRealDirs/UniqueRealFiles above, while the Entries
/// for virtual directories/files are owned by
/// VirtualDirectoryEntries/VirtualFileEntries above.
///
- llvm::StringMap<DirectoryEntry*, llvm::BumpPtrAllocator> SeenDirEntries;
+ llvm::StringMap<llvm::ErrorOr<DirectoryEntry &>, llvm::BumpPtrAllocator>
+ SeenDirEntries;
+
+ /// A reference to the file entry that is associated with a particular
+ /// filename, or a reference to another filename that should be looked up
+ /// instead of the accessed filename.
+ ///
+ /// The reference to another filename is specifically useful for Redirecting
+ /// VFSs that use external names. In that case, the \c FileEntryRef returned
+ /// by the \c FileManager will have the external name, and not the name that
+ /// was used to lookup the file.
+ using SeenFileEntryOrRedirect =
+ llvm::PointerUnion<FileEntry *, const StringRef *>;
/// A cache that maps paths to file entries (either real or
- /// virtual) we have looked up.
+ /// virtual) we have looked up, or an error that occurred when we looked up
+ /// the file.
///
/// \see SeenDirEntries
- llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> SeenFileEntries;
+ llvm::StringMap<llvm::ErrorOr<SeenFileEntryOrRedirect>,
+ llvm::BumpPtrAllocator>
+ SeenFileEntries;
/// The canonical names of directories.
llvm::DenseMap<const DirectoryEntry *, llvm::StringRef> CanonicalDirNames;
@@ -157,15 +232,12 @@ class FileManager : public RefCountedBase<FileManager> {
///
unsigned NextFileUID;
- // Statistics.
- unsigned NumDirLookups, NumFileLookups;
- unsigned NumDirCacheMisses, NumFileCacheMisses;
-
// Caching.
std::unique_ptr<FileSystemStatCache> StatCache;
- bool getStatValue(StringRef Path, llvm::vfs::Status &Status, bool isFile,
- std::unique_ptr<llvm::vfs::File> *F);
+ std::error_code getStatValue(StringRef Path, llvm::vfs::Status &Status,
+ bool isFile,
+ std::unique_ptr<llvm::vfs::File> *F);
/// Add all ancestors of the given path (pointing to either a file
/// or a directory) as virtual directories.
@@ -195,27 +267,86 @@ public:
/// Removes the FileSystemStatCache object from the manager.
void clearStatCache();
+ /// Returns the number of unique real file entries cached by the file manager.
+ size_t getNumUniqueRealFiles() const { return UniqueRealFiles.size(); }
+
/// Lookup, cache, and verify the specified directory (real or
/// virtual).
///
- /// This returns NULL if the directory doesn't exist.
+ /// This returns a \c std::error_code if there was an error reading the
+ /// directory. On success, returns the reference to the directory entry
+ /// together with the exact path that was used to access a file by a
+ /// particular call to getDirectoryRef.
///
/// \param CacheFailure If true and the file does not exist, we'll cache
/// the failure to find this file.
- const DirectoryEntry *getDirectory(StringRef DirName,
- bool CacheFailure = true);
+ llvm::Expected<DirectoryEntryRef> getDirectoryRef(StringRef DirName,
+ bool CacheFailure = true);
+
+ /// Get a \c DirectoryEntryRef if it exists, without doing anything on error.
+ llvm::Optional<DirectoryEntryRef>
+ getOptionalDirectoryRef(StringRef DirName, bool CacheFailure = true) {
+ return llvm::expectedToOptional(getDirectoryRef(DirName, CacheFailure));
+ }
+
+ /// Lookup, cache, and verify the specified directory (real or
+ /// virtual).
+ ///
+ /// This function is deprecated and will be removed at some point in the
+ /// future, new clients should use
+ /// \c getDirectoryRef.
+ ///
+ /// This returns a \c std::error_code if there was an error reading the
+ /// directory. If there is no error, the DirectoryEntry is guaranteed to be
+ /// non-NULL.
+ ///
+ /// \param CacheFailure If true and the file does not exist, we'll cache
+ /// the failure to find this file.
+ llvm::ErrorOr<const DirectoryEntry *>
+ getDirectory(StringRef DirName, bool CacheFailure = true);
/// Lookup, cache, and verify the specified file (real or
/// virtual).
///
- /// This returns NULL if the file doesn't exist.
+ /// This function is deprecated and will be removed at some point in the
+ /// future, new clients should use
+ /// \c getFileRef.
+ ///
+ /// This returns a \c std::error_code if there was an error loading the file.
+ /// If there is no error, the FileEntry is guaranteed to be non-NULL.
///
/// \param OpenFile if true and the file exists, it will be opened.
///
/// \param CacheFailure If true and the file does not exist, we'll cache
/// the failure to find this file.
- const FileEntry *getFile(StringRef Filename, bool OpenFile = false,
- bool CacheFailure = true);
+ llvm::ErrorOr<const FileEntry *>
+ getFile(StringRef Filename, bool OpenFile = false, bool CacheFailure = true);
+
+ /// Lookup, cache, and verify the specified file (real or virtual). Return the
+ /// reference to the file entry together with the exact path that was used to
+ /// access a file by a particular call to getFileRef. If the underlying VFS is
+ /// a redirecting VFS that uses external file names, the returned FileEntryRef
+ /// will use the external name instead of the filename that was passed to this
+ /// method.
+ ///
+ /// This returns a \c std::error_code if there was an error loading the file,
+ /// or a \c FileEntryRef otherwise.
+ ///
+ /// \param OpenFile if true and the file exists, it will be opened.
+ ///
+ /// \param CacheFailure If true and the file does not exist, we'll cache
+ /// the failure to find this file.
+ llvm::Expected<FileEntryRef> getFileRef(StringRef Filename,
+ bool OpenFile = false,
+ bool CacheFailure = true);
+
+ /// Get a FileEntryRef if it exists, without doing anything on error.
+ llvm::Optional<FileEntryRef> getOptionalFileRef(StringRef Filename,
+ bool OpenFile = false,
+ bool CacheFailure = true) {
+ return llvm::expectedToOptional(
+ getFileRef(Filename, OpenFile, CacheFailure));
+ }
/// Returns the current file system options
FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; }
@@ -223,6 +354,10 @@ public:
llvm::vfs::FileSystem &getVirtualFileSystem() const { return *FS; }
+ void setVirtualFileSystem(IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {
+ this->FS = std::move(FS);
+ }
+
/// Retrieve a file entry for a "virtual" file that acts as
/// if there were a file with the given name on disk.
///
@@ -230,24 +365,38 @@ public:
const FileEntry *getVirtualFile(StringRef Filename, off_t Size,
time_t ModificationTime);
+ /// Retrieve a FileEntry that bypasses VFE, which is expected to be a virtual
+ /// file entry, to access the real file. The returned FileEntry will have
+ /// the same filename as FE but a different identity and its own stat.
+ ///
+ /// This should be used only for rare error recovery paths because it
+ /// bypasses all mapping and uniquing, blindly creating a new FileEntry.
+ /// There is no attempt to deduplicate these; if you bypass the same file
+ /// twice, you get two new file entries.
+ llvm::Optional<FileEntryRef> getBypassFile(FileEntryRef VFE);
+
/// Open the specified file as a MemoryBuffer, returning a new
/// MemoryBuffer if successful, otherwise returning null.
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
- getBufferForFile(const FileEntry *Entry, bool isVolatile = false,
- bool ShouldCloseOpenFile = true);
+ getBufferForFile(const FileEntry *Entry, bool isVolatile = false);
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ getBufferForFile(StringRef Filename, bool isVolatile = false) {
+ return getBufferForFileImpl(Filename, /*FileSize=*/-1, isVolatile);
+ }
+
+private:
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
- getBufferForFile(StringRef Filename, bool isVolatile = false);
+ getBufferForFileImpl(StringRef Filename, int64_t FileSize, bool isVolatile);
+public:
/// Get the 'stat' information for the given \p Path.
///
/// If the path is relative, it will be resolved against the WorkingDir of the
/// FileManager's FileSystemOptions.
///
- /// \returns false on success, true on error.
- bool getNoncachedStatValue(StringRef Path, llvm::vfs::Status &Result);
-
- /// Remove the real file \p Entry from the cache.
- void invalidateCache(const FileEntry *Entry);
+ /// \returns a \c std::error_code describing an error, if there was one
+ std::error_code getNoncachedStatValue(StringRef Path,
+ llvm::vfs::Status &Result);
/// If path is not absolute and FileSystemOptions set the working
/// directory, the path is modified to be relative to the given
@@ -265,11 +414,6 @@ public:
void GetUniqueIDMapping(
SmallVectorImpl<const FileEntry *> &UIDToFiles) const;
- /// Modifies the size and modification time of a previously created
- /// FileEntry. Use with caution.
- static void modifyFileEntry(FileEntry *File, off_t Size,
- time_t ModificationTime);
-
/// Retrieve the canonical name for a given directory.
///
/// This is a very expensive operation, despite its results being cached,
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index 465486ede715..37d7198c6401 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -750,6 +750,12 @@ public:
return getIdentifierInfoFlag() == ZeroArg;
}
+ /// If this selector is the specific keyword selector described by Names.
+ bool isKeywordSelector(ArrayRef<StringRef> Names) const;
+
+ /// If this selector is the specific unary selector described by Name.
+ bool isUnarySelector(StringRef Name) const;
+
unsigned getNumArgs() const;
/// Retrieve the identifier at a given position in the selector.
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index 31aca2b0d695..a423654d5e03 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -111,6 +111,7 @@ BENIGN_LANGOPT(DollarIdents , 1, 1, "'$' in identifiers")
BENIGN_LANGOPT(AsmPreprocessor, 1, 0, "preprocessor in asm mode")
LANGOPT(GNUMode , 1, 1, "GNU extensions")
LANGOPT(GNUKeywords , 1, 1, "GNU keywords")
+VALUE_LANGOPT(GNUCVersion , 32, 0, "GNU C compatibility version")
BENIGN_LANGOPT(ImplicitInt, 1, !C99 && !CPlusPlus, "C89 implicit 'int'")
LANGOPT(Digraphs , 1, 0, "digraphs")
BENIGN_LANGOPT(HexFloats , 1, C99, "C99 hexadecimal float constants")
@@ -119,7 +120,8 @@ LANGOPT(AppleKext , 1, 0, "Apple kext support")
BENIGN_LANGOPT(PascalStrings, 1, 0, "Pascal string support")
LANGOPT(WritableStrings , 1, 0, "writable string support")
LANGOPT(ConstStrings , 1, 0, "const-qualified string support")
-LANGOPT(LaxVectorConversions , 1, 1, "lax vector conversions")
+ENUM_LANGOPT(LaxVectorConversions, LaxVectorConversionKind, 2,
+ LaxVectorConversionKind::All, "lax vector conversions")
LANGOPT(AltiVec , 1, 0, "AltiVec-style vector initializers")
LANGOPT(ZVector , 1, 0, "System z vector extensions")
LANGOPT(Exceptions , 1, 0, "exception handling")
@@ -128,6 +130,7 @@ LANGOPT(CXXExceptions , 1, 0, "C++ exceptions")
LANGOPT(DWARFExceptions , 1, 0, "dwarf exception handling")
LANGOPT(SjLjExceptions , 1, 0, "setjmp-longjump exception handling")
LANGOPT(SEHExceptions , 1, 0, "SEH .xdata exception handling")
+LANGOPT(WasmExceptions , 1, 0, "WebAssembly exception handling")
LANGOPT(ExternCNoUnwind , 1, 0, "Assume extern C functions don't unwind")
LANGOPT(TraditionalCPP , 1, 0, "traditional CPP emulation")
LANGOPT(RTTI , 1, 1, "run-time type information")
@@ -224,6 +227,8 @@ LANGOPT(GPURelocatableDeviceCode, 1, 0, "generate relocatable device code")
LANGOPT(SYCLIsDevice , 1, 0, "Generate code for SYCL device")
+LANGOPT(HIPUseNewLaunchAPI, 1, 0, "Use new kernel launching API for HIP")
+
LANGOPT(SizedDeallocation , 1, 0, "sized deallocation")
LANGOPT(AlignedAllocation , 1, 0, "aligned allocation")
LANGOPT(AlignedAllocationUnavailable, 1, 0, "aligned allocation functions are unavailable")
@@ -288,6 +293,10 @@ BENIGN_LANGOPT(ConstexprCallDepth, 32, 512,
"maximum constexpr call depth")
BENIGN_LANGOPT(ConstexprStepLimit, 32, 1048576,
"maximum constexpr evaluation steps")
+BENIGN_LANGOPT(EnableNewConstInterp, 1, 0,
+ "enable the experimental new constant interpreter")
+BENIGN_LANGOPT(ForceNewConstInterp, 1, 0,
+ "force the use of the experimental new constant interpreter")
BENIGN_LANGOPT(BracketDepth, 32, 256,
"maximum bracket nesting depth")
BENIGN_LANGOPT(NumLargeByValueCopy, 32, 0,
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index 8099eed28c5e..5f808f04e9ae 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -138,6 +138,12 @@ public:
/// rather than returning the required alignment.
Ver7,
+ /// Attempt to be ABI-compatible with code generated by Clang 9.0.x
+ /// (SVN r351319). This causes vectors of __int128 to be passed in memory
+ /// instead of passing in multiple scalar registers on x86_64 on Linux and
+ /// NetBSD.
+ Ver9,
+
/// Conform to the underlying platform's C and C++ ABIs as closely
/// as we can.
Latest
@@ -178,6 +184,16 @@ public:
FEA_On
};
+ enum class LaxVectorConversionKind {
+ /// Permit no implicit vector bitcasts.
+ None,
+ /// Permit vector bitcasts between integer vectors with different numbers
+ /// of elements but the same total bit-width.
+ Integer,
+ /// Permit vector bitcasts between all vectors with the same total
+ /// bit-width.
+ All,
+ };
public:
/// Set of enabled sanitizers.
diff --git a/include/clang/Frontend/LangStandard.h b/include/clang/Basic/LangStandard.h
index 244f14c793de..e7deb7d64638 100644
--- a/include/clang/Frontend/LangStandard.h
+++ b/include/clang/Basic/LangStandard.h
@@ -6,16 +6,37 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_FRONTEND_LANGSTANDARD_H
-#define LLVM_CLANG_FRONTEND_LANGSTANDARD_H
+#ifndef LLVM_CLANG_BASIC_LANGSTANDARD_H
+#define LLVM_CLANG_BASIC_LANGSTANDARD_H
#include "clang/Basic/LLVM.h"
-#include "clang/Frontend/FrontendOptions.h"
#include "llvm/ADT/StringRef.h"
namespace clang {
-namespace frontend {
+/// The language for the input, used to select and validate the language
+/// standard and possible actions.
+enum class Language : uint8_t {
+ Unknown,
+
+ /// Assembly: we accept this only so that we can preprocess it.
+ Asm,
+
+ /// LLVM IR: we accept this so that we can run the optimizer on it,
+ /// and compile it to assembly or object code.
+ LLVM_IR,
+
+ ///@{ Languages that the frontend can parse and compile.
+ C,
+ CXX,
+ ObjC,
+ ObjCXX,
+ OpenCL,
+ CUDA,
+ RenderScript,
+ HIP,
+ ///@}
+};
enum LangFeatures {
LineComment = (1 << 0),
@@ -35,22 +56,20 @@ enum LangFeatures {
OpenCL = (1 << 14)
};
-}
-
/// LangStandard - Information about the properties of a particular language
/// standard.
struct LangStandard {
enum Kind {
#define LANGSTANDARD(id, name, lang, desc, features) \
lang_##id,
-#include "clang/Frontend/LangStandards.def"
+#include "clang/Basic/LangStandards.def"
lang_unspecified
};
const char *ShortName;
const char *Description;
unsigned Flags;
- InputKind::Language Language;
+ clang::Language Language;
public:
/// getName - Get the name of this standard.
@@ -60,54 +79,54 @@ public:
const char *getDescription() const { return Description; }
/// Get the language that this standard describes.
- InputKind::Language getLanguage() const { return Language; }
+ clang::Language getLanguage() const { return Language; }
/// Language supports '//' comments.
- bool hasLineComments() const { return Flags & frontend::LineComment; }
+ bool hasLineComments() const { return Flags & LineComment; }
/// isC99 - Language is a superset of C99.
- bool isC99() const { return Flags & frontend::C99; }
+ bool isC99() const { return Flags & C99; }
/// isC11 - Language is a superset of C11.
- bool isC11() const { return Flags & frontend::C11; }
+ bool isC11() const { return Flags & C11; }
/// isC17 - Language is a superset of C17.
- bool isC17() const { return Flags & frontend::C17; }
+ bool isC17() const { return Flags & C17; }
/// isC2x - Language is a superset of C2x.
- bool isC2x() const { return Flags & frontend::C2x; }
+ bool isC2x() const { return Flags & C2x; }
/// isCPlusPlus - Language is a C++ variant.
- bool isCPlusPlus() const { return Flags & frontend::CPlusPlus; }
+ bool isCPlusPlus() const { return Flags & CPlusPlus; }
/// isCPlusPlus11 - Language is a C++11 variant (or later).
- bool isCPlusPlus11() const { return Flags & frontend::CPlusPlus11; }
+ bool isCPlusPlus11() const { return Flags & CPlusPlus11; }
/// isCPlusPlus14 - Language is a C++14 variant (or later).
- bool isCPlusPlus14() const { return Flags & frontend::CPlusPlus14; }
+ bool isCPlusPlus14() const { return Flags & CPlusPlus14; }
/// isCPlusPlus17 - Language is a C++17 variant (or later).
- bool isCPlusPlus17() const { return Flags & frontend::CPlusPlus17; }
+ bool isCPlusPlus17() const { return Flags & CPlusPlus17; }
/// isCPlusPlus2a - Language is a post-C++17 variant (or later).
- bool isCPlusPlus2a() const { return Flags & frontend::CPlusPlus2a; }
-
+ bool isCPlusPlus2a() const { return Flags & CPlusPlus2a; }
/// hasDigraphs - Language supports digraphs.
- bool hasDigraphs() const { return Flags & frontend::Digraphs; }
+ bool hasDigraphs() const { return Flags & Digraphs; }
/// isGNUMode - Language includes GNU extensions.
- bool isGNUMode() const { return Flags & frontend::GNUMode; }
+ bool isGNUMode() const { return Flags & GNUMode; }
/// hasHexFloats - Language supports hexadecimal float constants.
- bool hasHexFloats() const { return Flags & frontend::HexFloat; }
+ bool hasHexFloats() const { return Flags & HexFloat; }
/// hasImplicitInt - Language allows variables to be typed as int implicitly.
- bool hasImplicitInt() const { return Flags & frontend::ImplicitInt; }
+ bool hasImplicitInt() const { return Flags & ImplicitInt; }
/// isOpenCL - Language is a OpenCL variant.
- bool isOpenCL() const { return Flags & frontend::OpenCL; }
+ bool isOpenCL() const { return Flags & OpenCL; }
+ static Kind getLangKind(StringRef Name);
static const LangStandard &getLangStandardForKind(Kind K);
static const LangStandard *getLangStandardForName(StringRef Name);
};
diff --git a/include/clang/Frontend/LangStandards.def b/include/clang/Basic/LangStandards.def
index 0964e9b90a03..427691fb71e9 100644
--- a/include/clang/Frontend/LangStandards.def
+++ b/include/clang/Basic/LangStandards.def
@@ -14,7 +14,7 @@
///
/// \param IDENT - The name of the standard as a C++ identifier.
/// \param NAME - The name of the standard.
-/// \param LANG - The InputKind::Language for which this is a standard.
+/// \param LANG - The Language for which this is a standard.
/// \param DESC - A short description of the standard.
/// \param FEATURES - The standard features as flags, these are enums from the
/// clang::frontend namespace, which is assumed to be be available.
@@ -165,7 +165,7 @@ LANGSTANDARD(opencl12, "cl1.2",
LANGSTANDARD(opencl20, "cl2.0",
OpenCL, "OpenCL 2.0",
LineComment | C99 | Digraphs | HexFloat | OpenCL)
-LANGSTANDARD(openclcpp, "c++",
+LANGSTANDARD(openclcpp, "clc++",
OpenCL, "C++ for OpenCL",
LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 |
Digraphs | HexFloat | OpenCL)
@@ -174,6 +174,7 @@ LANGSTANDARD_ALIAS_DEPR(opencl10, "CL")
LANGSTANDARD_ALIAS_DEPR(opencl11, "CL1.1")
LANGSTANDARD_ALIAS_DEPR(opencl12, "CL1.2")
LANGSTANDARD_ALIAS_DEPR(opencl20, "CL2.0")
+LANGSTANDARD_ALIAS_DEPR(openclcpp, "CLC++")
// CUDA
LANGSTANDARD(cuda, "cuda", CUDA, "NVIDIA CUDA(tm)",
diff --git a/include/clang/Basic/Linkage.h b/include/clang/Basic/Linkage.h
index 696f85b18535..f4d442c084cf 100644
--- a/include/clang/Basic/Linkage.h
+++ b/include/clang/Basic/Linkage.h
@@ -82,6 +82,12 @@ inline bool isDiscardableGVALinkage(GVALinkage L) {
return L <= GVA_DiscardableODR;
}
+/// Do we know that this will be the only definition of this symbol (excluding
+/// inlining-only definitions)?
+inline bool isUniqueGVALinkage(GVALinkage L) {
+ return L == GVA_Internal || L == GVA_StrongExternal;
+}
+
inline bool isExternallyVisible(Linkage L) {
return L >= VisibleNoLinkage;
}
diff --git a/include/clang/Basic/OpenCLOptions.h b/include/clang/Basic/OpenCLOptions.h
index 47310da1d6d9..15661154eab5 100644
--- a/include/clang/Basic/OpenCLOptions.h
+++ b/include/clang/Basic/OpenCLOptions.h
@@ -42,7 +42,7 @@ public:
// Is supported as either an extension or an (optional) core feature for
// OpenCL version \p CLVer.
- bool isSupported(llvm::StringRef Ext, LangOptions LO) const {
+ bool isSupported(llvm::StringRef Ext, const LangOptions &LO) const {
// In C++ mode all extensions should work at least as in v2.0.
auto CLVer = LO.OpenCLCPlusPlus ? 200 : LO.OpenCLVersion;
auto I = OptMap.find(Ext)->getValue();
@@ -51,7 +51,7 @@ public:
// Is supported (optional) OpenCL core features for OpenCL version \p CLVer.
// For supported extension, return false.
- bool isSupportedCore(llvm::StringRef Ext, LangOptions LO) const {
+ bool isSupportedCore(llvm::StringRef Ext, const LangOptions &LO) const {
// In C++ mode all extensions should work at least as in v2.0.
auto CLVer = LO.OpenCLCPlusPlus ? 200 : LO.OpenCLVersion;
auto I = OptMap.find(Ext)->getValue();
@@ -60,7 +60,7 @@ public:
// Is supported OpenCL extension for OpenCL version \p CLVer.
// For supported (optional) core feature, return false.
- bool isSupportedExtension(llvm::StringRef Ext, LangOptions LO) const {
+ bool isSupportedExtension(llvm::StringRef Ext, const LangOptions &LO) const {
// In C++ mode all extensions should work at least as in v2.0.
auto CLVer = LO.OpenCLCPlusPlus ? 200 : LO.OpenCLVersion;
auto I = OptMap.find(Ext)->getValue();
diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def
index 9685af4cade8..ff8f07aa5def 100644
--- a/include/clang/Basic/OpenMPKinds.def
+++ b/include/clang/Basic/OpenMPKinds.def
@@ -92,6 +92,15 @@
#ifndef OPENMP_TASKLOOP_SIMD_CLAUSE
# define OPENMP_TASKLOOP_SIMD_CLAUSE(Name)
#endif
+#ifndef OPENMP_MASTER_TASKLOOP_CLAUSE
+# define OPENMP_MASTER_TASKLOOP_CLAUSE(Name)
+#endif
+#ifndef OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE
+# define OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(Name)
+#endif
+#ifndef OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE
+# define OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(Name)
+#endif
#ifndef OPENMP_CRITICAL_CLAUSE
# define OPENMP_CRITICAL_CLAUSE(Name)
#endif
@@ -191,6 +200,15 @@
#ifndef OPENMP_ALLOCATE_CLAUSE
# define OPENMP_ALLOCATE_CLAUSE(Name)
#endif
+#ifndef OPENMP_DEVICE_TYPE_KIND
+#define OPENMP_DEVICE_TYPE_KIND(Name)
+#endif
+#ifndef OPENMP_DECLARE_VARIANT_CLAUSE
+#define OPENMP_DECLARE_VARIANT_CLAUSE(Name)
+#endif
+#ifndef OPENMP_MATCH_KIND
+#define OPENMP_MATCH_KIND(Name)
+#endif
// OpenMP directives.
OPENMP_DIRECTIVE(threadprivate)
@@ -248,6 +266,10 @@ OPENMP_DIRECTIVE_EXT(target_teams_distribute_parallel_for, "target teams distrib
OPENMP_DIRECTIVE_EXT(target_teams_distribute_parallel_for_simd, "target teams distribute parallel for simd")
OPENMP_DIRECTIVE_EXT(target_teams_distribute_simd, "target teams distribute simd")
OPENMP_DIRECTIVE(allocate)
+OPENMP_DIRECTIVE_EXT(declare_variant, "declare variant")
+OPENMP_DIRECTIVE_EXT(master_taskloop, "master taskloop")
+OPENMP_DIRECTIVE_EXT(parallel_master_taskloop, "parallel master taskloop")
+OPENMP_DIRECTIVE_EXT(master_taskloop_simd, "master taskloop simd")
// OpenMP clauses.
OPENMP_CLAUSE(allocator, OMPAllocatorClause)
@@ -656,6 +678,69 @@ OPENMP_TASKLOOP_SIMD_CLAUSE(reduction)
OPENMP_TASKLOOP_SIMD_CLAUSE(in_reduction)
OPENMP_TASKLOOP_SIMD_CLAUSE(allocate)
+// Clauses allowed for OpenMP directive 'master taskloop'.
+OPENMP_MASTER_TASKLOOP_CLAUSE(if)
+OPENMP_MASTER_TASKLOOP_CLAUSE(shared)
+OPENMP_MASTER_TASKLOOP_CLAUSE(private)
+OPENMP_MASTER_TASKLOOP_CLAUSE(firstprivate)
+OPENMP_MASTER_TASKLOOP_CLAUSE(lastprivate)
+OPENMP_MASTER_TASKLOOP_CLAUSE(default)
+OPENMP_MASTER_TASKLOOP_CLAUSE(collapse)
+OPENMP_MASTER_TASKLOOP_CLAUSE(final)
+OPENMP_MASTER_TASKLOOP_CLAUSE(untied)
+OPENMP_MASTER_TASKLOOP_CLAUSE(mergeable)
+OPENMP_MASTER_TASKLOOP_CLAUSE(priority)
+OPENMP_MASTER_TASKLOOP_CLAUSE(grainsize)
+OPENMP_MASTER_TASKLOOP_CLAUSE(nogroup)
+OPENMP_MASTER_TASKLOOP_CLAUSE(num_tasks)
+OPENMP_MASTER_TASKLOOP_CLAUSE(reduction)
+OPENMP_MASTER_TASKLOOP_CLAUSE(in_reduction)
+OPENMP_MASTER_TASKLOOP_CLAUSE(allocate)
+
+// Clauses allowed for OpenMP directive 'master taskloop simd'.
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(if)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(shared)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(private)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(firstprivate)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(lastprivate)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(default)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(collapse)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(final)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(untied)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(mergeable)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(priority)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(linear)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(aligned)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(safelen)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(simdlen)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(grainsize)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(nogroup)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(num_tasks)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(reduction)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(in_reduction)
+OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(allocate)
+
+// Clauses allowed for OpenMP directive 'parallel master taskloop'.
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(if)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(shared)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(private)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(firstprivate)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(lastprivate)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(default)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(collapse)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(final)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(untied)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(mergeable)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(priority)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(grainsize)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(nogroup)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(num_tasks)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(reduction)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(allocate)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(num_threads)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(proc_bind)
+OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(copyin)
+
// Clauses allowed for OpenMP directive 'critical'.
OPENMP_CRITICAL_CLAUSE(hint)
@@ -950,9 +1035,27 @@ OPENMP_TASKGROUP_CLAUSE(allocate)
// Clauses allowed for OpenMP directive 'declare mapper'.
OPENMP_DECLARE_MAPPER_CLAUSE(map)
+// Device types for 'device_type' clause.
+OPENMP_DEVICE_TYPE_KIND(host)
+OPENMP_DEVICE_TYPE_KIND(nohost)
+OPENMP_DEVICE_TYPE_KIND(any)
+
+// Clauses allowed for OpenMP directive 'declare variant'.
+OPENMP_DECLARE_VARIANT_CLAUSE(match)
+
+// Context selectors for 'match' clause.
+// TODO: add other context selectors.
+OPENMP_MATCH_KIND(implementation)
+
+#undef OPENMP_MATCH_KIND
+#undef OPENMP_DECLARE_VARIANT_CLAUSE
+#undef OPENMP_DEVICE_TYPE_KIND
#undef OPENMP_ALLOCATE_CLAUSE
#undef OPENMP_DECLARE_MAPPER_CLAUSE
#undef OPENMP_TASKGROUP_CLAUSE
+#undef OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE
+#undef OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE
+#undef OPENMP_MASTER_TASKLOOP_CLAUSE
#undef OPENMP_TASKLOOP_SIMD_CLAUSE
#undef OPENMP_TASKLOOP_CLAUSE
#undef OPENMP_LINEAR_KIND
diff --git a/include/clang/Basic/OpenMPKinds.h b/include/clang/Basic/OpenMPKinds.h
index d8dee2310ec2..4129cca0fe68 100644
--- a/include/clang/Basic/OpenMPKinds.h
+++ b/include/clang/Basic/OpenMPKinds.h
@@ -35,6 +35,8 @@ enum OpenMPClauseKind {
#include "clang/Basic/OpenMPKinds.def"
OMPC_threadprivate,
OMPC_uniform,
+ OMPC_device_type,
+ OMPC_match,
OMPC_unknown
};
@@ -152,6 +154,14 @@ enum OpenMPAtomicDefaultMemOrderClauseKind {
OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown
};
+/// OpenMP device type for 'device_type' clause.
+enum OpenMPDeviceType {
+#define OPENMP_DEVICE_TYPE_KIND(Name) \
+ OMPC_DEVICE_TYPE_##Name,
+#include "clang/Basic/OpenMPKinds.def"
+ OMPC_DEVICE_TYPE_unknown
+};
+
/// Scheduling data for loop-based OpenMP directives.
struct OpenMPScheduleTy final {
OpenMPScheduleClauseKind Schedule = OMPC_SCHEDULE_unknown;
@@ -259,7 +269,8 @@ bool isOpenMPPrivate(OpenMPClauseKind Kind);
bool isOpenMPThreadPrivate(OpenMPClauseKind Kind);
/// Checks if the specified directive kind is one of tasking directives - task,
-/// taskloop or taksloop simd.
+/// taskloop, taksloop simd, master taskloop, parallel master taskloop or master
+/// taskloop simd.
bool isOpenMPTaskingDirective(OpenMPDirectiveKind Kind);
/// Checks if the specified directive kind is one of the composite or combined
diff --git a/include/clang/Basic/OperatorKinds.h b/include/clang/Basic/OperatorKinds.h
index 9757acaa5300..d66189144511 100644
--- a/include/clang/Basic/OperatorKinds.h
+++ b/include/clang/Basic/OperatorKinds.h
@@ -30,6 +30,25 @@ enum OverloadedOperatorKind : int {
/// the preceding "operator" keyword.
const char *getOperatorSpelling(OverloadedOperatorKind Operator);
+/// Get the other overloaded operator that the given operator can be rewritten
+/// into, if any such operator exists.
+inline OverloadedOperatorKind
+getRewrittenOverloadedOperator(OverloadedOperatorKind Kind) {
+ switch (Kind) {
+ case OO_Less:
+ case OO_LessEqual:
+ case OO_Greater:
+ case OO_GreaterEqual:
+ return OO_Spaceship;
+
+ case OO_ExclaimEqual:
+ return OO_EqualEqual;
+
+ default:
+ return OO_None;
+ }
+}
+
} // end namespace clang
#endif
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index e32f749ae6ab..3185ca0f4a25 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -140,9 +140,9 @@ namespace SrcMgr {
/// exist.
unsigned BufferOverridden : 1;
- /// True if this content cache was initially created for a source
- /// file considered as a system one.
- unsigned IsSystemFile : 1;
+ /// True if this content cache was initially created for a source file
+ /// considered to be volatile (likely to change between stat and open).
+ unsigned IsFileVolatile : 1;
/// True if this file may be transient, that is, if it might not
/// exist at some later point in time when this content entry is used,
@@ -152,15 +152,15 @@ namespace SrcMgr {
ContentCache(const FileEntry *Ent = nullptr) : ContentCache(Ent, Ent) {}
ContentCache(const FileEntry *Ent, const FileEntry *contentEnt)
- : Buffer(nullptr, false), OrigEntry(Ent), ContentsEntry(contentEnt),
- BufferOverridden(false), IsSystemFile(false), IsTransient(false) {}
+ : Buffer(nullptr, false), OrigEntry(Ent), ContentsEntry(contentEnt),
+ BufferOverridden(false), IsFileVolatile(false), IsTransient(false) {}
/// 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(nullptr, false), BufferOverridden(false), IsSystemFile(false),
- IsTransient(false) {
+ : Buffer(nullptr, false), BufferOverridden(false),
+ IsFileVolatile(false), IsTransient(false) {
OrigEntry = RHS.OrigEntry;
ContentsEntry = RHS.ContentsEntry;
@@ -185,7 +185,7 @@ namespace SrcMgr {
///
/// \param Invalid If non-NULL, will be set \c true if an error occurred.
const llvm::MemoryBuffer *getBuffer(DiagnosticsEngine &Diag,
- const SourceManager &SM,
+ FileManager &FM,
SourceLocation Loc = SourceLocation(),
bool *Invalid = nullptr) const;
@@ -265,16 +265,21 @@ namespace SrcMgr {
llvm::PointerIntPair<const ContentCache*, 3, CharacteristicKind>
ContentAndKind;
+ /// The filename that is used to access the file entry represented by the
+ /// content cache.
+ StringRef Filename;
+
public:
/// Return a FileInfo object.
static FileInfo get(SourceLocation IL, const ContentCache *Con,
- CharacteristicKind FileCharacter) {
+ CharacteristicKind FileCharacter, StringRef Filename) {
FileInfo X;
X.IncludeLoc = IL.getRawEncoding();
X.NumCreatedFIDs = 0;
X.HasLineDirectives = false;
X.ContentAndKind.setPointer(Con);
X.ContentAndKind.setInt(FileCharacter);
+ X.Filename = Filename;
return X;
}
@@ -299,6 +304,10 @@ namespace SrcMgr {
void setHasLineDirectives() {
HasLineDirectives = true;
}
+
+ /// Returns the name of the file that was used when the file was loaded from
+ /// the underlying file system.
+ StringRef getName() const { return Filename; }
};
/// Each ExpansionInfo encodes the expansion location - where
@@ -821,7 +830,18 @@ public:
const SrcMgr::ContentCache *IR =
getOrCreateContentCache(SourceFile, isSystem(FileCharacter));
assert(IR && "getOrCreateContentCache() cannot return NULL");
- return createFileID(IR, IncludePos, FileCharacter, LoadedID, LoadedOffset);
+ return createFileID(IR, SourceFile->getName(), IncludePos, FileCharacter,
+ LoadedID, LoadedOffset);
+ }
+
+ FileID createFileID(FileEntryRef SourceFile, SourceLocation IncludePos,
+ SrcMgr::CharacteristicKind FileCharacter,
+ int LoadedID = 0, unsigned LoadedOffset = 0) {
+ const SrcMgr::ContentCache *IR = getOrCreateContentCache(
+ &SourceFile.getFileEntry(), isSystem(FileCharacter));
+ assert(IR && "getOrCreateContentCache() cannot return NULL");
+ return createFileID(IR, SourceFile.getName(), IncludePos, FileCharacter,
+ LoadedID, LoadedOffset);
}
/// Create a new FileID that represents the specified memory buffer.
@@ -832,9 +852,10 @@ public:
SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User,
int LoadedID = 0, unsigned LoadedOffset = 0,
SourceLocation IncludeLoc = SourceLocation()) {
+ StringRef Name = Buffer->getBufferIdentifier();
return createFileID(
createMemBufferContentCache(Buffer.release(), /*DoNotFree*/ false),
- IncludeLoc, FileCharacter, LoadedID, LoadedOffset);
+ Name, IncludeLoc, FileCharacter, LoadedID, LoadedOffset);
}
enum UnownedTag { Unowned };
@@ -847,8 +868,9 @@ public:
SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User,
int LoadedID = 0, unsigned LoadedOffset = 0,
SourceLocation IncludeLoc = SourceLocation()) {
- return createFileID(createMemBufferContentCache(Buffer, /*DoNotFree*/true),
- IncludeLoc, FileCharacter, LoadedID, LoadedOffset);
+ return createFileID(createMemBufferContentCache(Buffer, /*DoNotFree*/ true),
+ Buffer->getBufferIdentifier(), IncludeLoc,
+ FileCharacter, LoadedID, LoadedOffset);
}
/// Get the FileID for \p SourceFile if it exists. Otherwise, create a
@@ -930,11 +952,12 @@ public:
return false;
}
- /// Disable overridding the contents of a file, previously enabled
- /// with #overrideFileContents.
+ /// Bypass the overridden contents of a file. This creates a new FileEntry
+ /// and initializes the content cache for it. Returns nullptr if there is no
+ /// such file in the filesystem.
///
/// This should be called before parsing has begun.
- void disableFileContentsOverride(const FileEntry *File);
+ const FileEntry *bypassFileContentsOverride(const FileEntry &File);
/// Specify that a file is transient.
void setFileIsTransient(const FileEntry *SourceFile);
@@ -964,8 +987,8 @@ public:
return getFakeBufferForRecovery();
}
- return Entry.getFile().getContentCache()->getBuffer(Diag, *this, Loc,
- Invalid);
+ return Entry.getFile().getContentCache()->getBuffer(Diag, getFileManager(),
+ Loc, Invalid);
}
const llvm::MemoryBuffer *getBuffer(FileID FID,
@@ -979,9 +1002,8 @@ public:
return getFakeBufferForRecovery();
}
- return Entry.getFile().getContentCache()->getBuffer(Diag, *this,
- SourceLocation(),
- Invalid);
+ return Entry.getFile().getContentCache()->getBuffer(
+ Diag, getFileManager(), SourceLocation(), Invalid);
}
/// Returns the FileEntry record for the provided FileID.
@@ -997,6 +1019,19 @@ public:
return Content->OrigEntry;
}
+ /// Returns the FileEntryRef for the provided FileID.
+ Optional<FileEntryRef> getFileEntryRefForID(FileID FID) const {
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
+ if (Invalid || !Entry.isFile())
+ return None;
+
+ const SrcMgr::ContentCache *Content = Entry.getFile().getContentCache();
+ if (!Content || !Content->OrigEntry)
+ return None;
+ return FileEntryRef(Entry.getFile().getName(), *Content->OrigEntry);
+ }
+
/// Returns the FileEntry record for the provided SLocEntry.
const FileEntry *getFileEntryForSLocEntry(const SrcMgr::SLocEntry &sloc) const
{
@@ -1785,10 +1820,10 @@ private:
///
/// This works regardless of whether the ContentCache corresponds to a
/// file or some other input source.
- FileID createFileID(const SrcMgr::ContentCache* File,
+ FileID createFileID(const SrcMgr::ContentCache *File, StringRef Filename,
SourceLocation IncludePos,
- SrcMgr::CharacteristicKind DirCharacter,
- int LoadedID, unsigned LoadedOffset);
+ SrcMgr::CharacteristicKind DirCharacter, int LoadedID,
+ unsigned LoadedOffset);
const SrcMgr::ContentCache *
getOrCreateContentCache(const FileEntry *SourceFile,
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index d1236e798e5d..fad97a26d957 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -32,7 +32,8 @@ namespace clang {
enum ConstexprSpecKind {
CSK_unspecified,
CSK_constexpr,
- CSK_consteval
+ CSK_consteval,
+ CSK_constinit
};
/// Specifies the width of a type, e.g., short, long, or long long.
diff --git a/include/clang/Basic/Stack.h b/include/clang/Basic/Stack.h
index e0b04099de58..3418c3bad11b 100644
--- a/include/clang/Basic/Stack.h
+++ b/include/clang/Basic/Stack.h
@@ -16,11 +16,40 @@
#include <cstddef>
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+
namespace clang {
/// The amount of stack space that Clang would like to be provided with.
/// If less than this much is available, we may be unable to reach our
/// template instantiation depth limit and other similar limits.
constexpr size_t DesiredStackSize = 8 << 20;
+
+ /// Call this once on each thread, as soon after starting the thread as
+ /// feasible, to note the approximate address of the bottom of the stack.
+ void noteBottomOfStack();
+
+ /// Determine whether the stack is nearly exhausted.
+ bool isStackNearlyExhausted();
+
+ void runWithSufficientStackSpaceSlow(llvm::function_ref<void()> Diag,
+ llvm::function_ref<void()> Fn);
+
+ /// Run a given function on a stack with "sufficient" space. If stack space
+ /// is insufficient, calls Diag to emit a diagnostic before calling Fn.
+ inline void runWithSufficientStackSpace(llvm::function_ref<void()> Diag,
+ llvm::function_ref<void()> Fn) {
+#ifdef LLVM_ENABLE_THREADS
+ if (LLVM_UNLIKELY(isStackNearlyExhausted()))
+ runWithSufficientStackSpaceSlow(Diag, Fn);
+ else
+ Fn();
+#else
+ if (LLVM_UNLIKELY(isStackNearlyExhausted()))
+ Diag();
+ Fn();
+#endif
+ }
} // end namespace clang
#endif // LLVM_CLANG_BASIC_STACK_H
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index be364de1a76c..59444b2919a9 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -114,6 +114,7 @@ def GNUNullExpr : DStmt<Expr>;
// C++ Expressions.
def CXXOperatorCallExpr : DStmt<CallExpr>;
def CXXMemberCallExpr : DStmt<CallExpr>;
+def CXXRewrittenBinaryOperator : DStmt<Expr>;
def CXXNamedCastExpr : DStmt<ExplicitCastExpr, 1>;
def CXXStaticCastExpr : DStmt<CXXNamedCastExpr>;
def CXXDynamicCastExpr : DStmt<CXXNamedCastExpr>;
@@ -163,6 +164,9 @@ def CoawaitExpr : DStmt<CoroutineSuspendExpr>;
def DependentCoawaitExpr : DStmt<Expr>;
def CoyieldExpr : DStmt<CoroutineSuspendExpr>;
+// C++2a Concepts expressions
+def ConceptSpecializationExpr : DStmt<Expr>;
+
// Obj-C Expressions.
def ObjCStringLiteral : DStmt<Expr>;
def ObjCBoxedExpr : DStmt<Expr>;
@@ -242,6 +246,9 @@ def OMPCancellationPointDirective : DStmt<OMPExecutableDirective>;
def OMPCancelDirective : DStmt<OMPExecutableDirective>;
def OMPTaskLoopDirective : DStmt<OMPLoopDirective>;
def OMPTaskLoopSimdDirective : DStmt<OMPLoopDirective>;
+def OMPMasterTaskLoopDirective : DStmt<OMPLoopDirective>;
+def OMPMasterTaskLoopSimdDirective : DStmt<OMPLoopDirective>;
+def OMPParallelMasterTaskLoopDirective : DStmt<OMPLoopDirective>;
def OMPDistributeDirective : DStmt<OMPLoopDirective>;
def OMPDistributeParallelForDirective : DStmt<OMPLoopDirective>;
def OMPDistributeParallelForSimdDirective : DStmt<OMPLoopDirective>;
diff --git a/include/clang/Basic/SyncScope.h b/include/clang/Basic/SyncScope.h
index 15af02d83cde..ce8fb9cbed13 100644
--- a/include/clang/Basic/SyncScope.h
+++ b/include/clang/Basic/SyncScope.h
@@ -144,7 +144,7 @@ AtomicScopeModel::create(AtomicScopeModelKind K) {
case AtomicScopeModelKind::None:
return std::unique_ptr<AtomicScopeModel>{};
case AtomicScopeModelKind::OpenCL:
- return llvm::make_unique<AtomicScopeOpenCLModel>();
+ return std::make_unique<AtomicScopeOpenCLModel>();
}
llvm_unreachable("Invalid atomic scope model kind");
}
diff --git a/include/clang/Basic/TargetBuiltins.h b/include/clang/Basic/TargetBuiltins.h
index 50262fa310ce..0e2f0753b0c5 100644
--- a/include/clang/Basic/TargetBuiltins.h
+++ b/include/clang/Basic/TargetBuiltins.h
@@ -52,6 +52,16 @@ namespace clang {
};
}
+ /// BPF builtins
+ namespace BPF {
+ enum {
+ LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1,
+ #define BUILTIN(ID, TYPE, ATTRS) BI##ID,
+ #include "clang/Basic/BuiltinsBPF.def"
+ LastTSBuiltin
+ };
+ }
+
/// PPC builtins
namespace PPC {
enum {
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 7a8384f5fbc0..9a3bb986930e 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -19,14 +19,15 @@
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetCXXABI.h"
#include "clang/Basic/TargetOptions.h"
+#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
-#include "llvm/IR/DataLayout.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/VersionTuple.h"
#include <cassert>
@@ -35,6 +36,7 @@
namespace llvm {
struct fltSemantics;
+class DataLayout;
}
namespace clang {
@@ -193,12 +195,12 @@ protected:
unsigned IsRenderScriptTarget : 1;
+ unsigned HasAArch64SVETypes : 1;
+
// TargetInfo Constructor. Default initializes all fields.
TargetInfo(const llvm::Triple &T);
- void resetDataLayout(StringRef DL) {
- DataLayout.reset(new llvm::DataLayout(DL));
- }
+ void resetDataLayout(StringRef DL);
public:
/// Construct a target for the given options.
@@ -789,6 +791,10 @@ public:
/// Returns true for RenderScript.
bool isRenderScriptTarget() const { return IsRenderScriptTarget; }
+ /// Returns whether or not the AArch64 SVE built-in types are
+ /// available on this target.
+ bool hasAArch64SVETypes() const { return HasAArch64SVETypes; }
+
/// Returns whether the passed in string is a valid clobber in an
/// inline asm statement.
///
@@ -1249,15 +1255,9 @@ public:
bool isBigEndian() const { return BigEndian; }
bool isLittleEndian() const { return !BigEndian; }
- enum CallingConvMethodType {
- CCMT_Unknown,
- CCMT_Member,
- CCMT_NonMember
- };
-
/// Gets the default calling convention for the given target and
/// declaration context.
- virtual CallingConv getDefaultCallingConv(CallingConvMethodType MT) const {
+ virtual CallingConv getDefaultCallingConv() const {
// Not all targets will specify an explicit calling convention that we can
// express. This will always do the right thing, even though it's not
// an explicit calling convention.
@@ -1268,6 +1268,7 @@ public:
CCCR_OK,
CCCR_Warning,
CCCR_Ignore,
+ CCCR_Error,
};
/// Determines whether a given calling convention is valid for the
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 55e94d387c9d..94fe1ba63a9f 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -68,6 +68,9 @@
#ifndef ANNOTATION
#define ANNOTATION(X) TOK(annot_ ## X)
#endif
+#ifndef PRAGMA_ANNOTATION
+#define PRAGMA_ANNOTATION(X) ANNOTATION(X)
+#endif
//===----------------------------------------------------------------------===//
// Preprocessor keywords.
@@ -386,6 +389,7 @@ MODULES_KEYWORD(import)
// C++20 keywords.
CXX2A_KEYWORD(char8_t , CHAR8SUPPORT)
CXX2A_KEYWORD(consteval , 0)
+CXX2A_KEYWORD(constinit , 0)
// C11 Extension
KEYWORD(_Float16 , KEYALL)
@@ -446,16 +450,18 @@ TYPE_TRAIT_N(__is_nothrow_constructible, IsNothrowConstructible, KEYCXX)
// MSVC14.0 / VS2015 Type Traits
TYPE_TRAIT_2(__is_assignable, IsAssignable, KEYCXX)
+// MSVC Type Traits of unknown vintage
+TYPE_TRAIT_1(__has_nothrow_move_assign, HasNothrowMoveAssign, KEYCXX)
+TYPE_TRAIT_1(__has_trivial_move_assign, HasTrivialMoveAssign, KEYCXX)
+TYPE_TRAIT_1(__has_trivial_move_constructor, HasTrivialMoveConstructor, KEYCXX)
+
// GNU and MS Type Traits
TYPE_TRAIT_1(__has_nothrow_assign, HasNothrowAssign, KEYCXX)
-TYPE_TRAIT_1(__has_nothrow_move_assign, HasNothrowMoveAssign, KEYCXX)
TYPE_TRAIT_1(__has_nothrow_copy, HasNothrowCopy, KEYCXX)
TYPE_TRAIT_1(__has_nothrow_constructor, HasNothrowConstructor, KEYCXX)
TYPE_TRAIT_1(__has_trivial_assign, HasTrivialAssign, KEYCXX)
-TYPE_TRAIT_1(__has_trivial_move_assign, HasTrivialMoveAssign, KEYCXX)
TYPE_TRAIT_1(__has_trivial_copy, HasTrivialCopy, KEYCXX)
TYPE_TRAIT_1(__has_trivial_constructor, HasTrivialDefaultConstructor, KEYCXX)
-TYPE_TRAIT_1(__has_trivial_move_constructor, HasTrivialMoveConstructor, KEYCXX)
TYPE_TRAIT_1(__has_trivial_destructor, HasTrivialDestructor, KEYCXX)
TYPE_TRAIT_1(__has_virtual_destructor, HasVirtualDestructor, KEYCXX)
TYPE_TRAIT_1(__is_abstract, IsAbstract, KEYCXX)
@@ -472,17 +478,18 @@ TYPE_TRAIT_1(__is_literal, IsLiteral, KEYCXX)
ALIAS("__is_literal_type", __is_literal, KEYCXX)
TYPE_TRAIT_1(__is_pod, IsPOD, KEYCXX)
TYPE_TRAIT_1(__is_polymorphic, IsPolymorphic, KEYCXX)
+TYPE_TRAIT_1(__is_standard_layout, IsStandardLayout, KEYCXX)
TYPE_TRAIT_1(__is_trivial, IsTrivial, KEYCXX)
+TYPE_TRAIT_2(__is_trivially_assignable, IsTriviallyAssignable, KEYCXX)
+TYPE_TRAIT_N(__is_trivially_constructible, IsTriviallyConstructible, KEYCXX)
+TYPE_TRAIT_1(__is_trivially_copyable, IsTriviallyCopyable, KEYCXX)
TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX)
TYPE_TRAIT_1(__has_unique_object_representations,
HasUniqueObjectRepresentations, KEYCXX)
+KEYWORD(__underlying_type , KEYCXX)
// Clang-only C++ Type Traits
-TYPE_TRAIT_N(__is_trivially_constructible, IsTriviallyConstructible, KEYCXX)
-TYPE_TRAIT_1(__is_trivially_copyable, IsTriviallyCopyable, KEYCXX)
-TYPE_TRAIT_2(__is_trivially_assignable, IsTriviallyAssignable, KEYCXX)
TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)
-KEYWORD(__underlying_type , KEYCXX)
// Embarcadero Expression Traits
KEYWORD(__is_lvalue_expr , KEYCXX)
@@ -509,7 +516,6 @@ TYPE_TRAIT_1(__is_member_function_pointer, IsMemberFunctionPointer, KEYCXX)
TYPE_TRAIT_1(__is_member_pointer, IsMemberPointer, KEYCXX)
TYPE_TRAIT_1(__is_const, IsConst, KEYCXX)
TYPE_TRAIT_1(__is_volatile, IsVolatile, KEYCXX)
-TYPE_TRAIT_1(__is_standard_layout, IsStandardLayout, KEYCXX)
TYPE_TRAIT_1(__is_signed, IsSigned, KEYCXX)
TYPE_TRAIT_1(__is_unsigned, IsUnsigned, KEYCXX)
@@ -722,6 +728,11 @@ ANNOTATION(typename) // annotation for a C typedef name, a C++ (possibly
ANNOTATION(template_id) // annotation for a C++ template-id that names a
// function template specialization (not a type),
// e.g., "std::swap<int>"
+ANNOTATION(non_type) // annotation for a single non-type declaration
+ANNOTATION(non_type_undeclared) // annotation for an undeclared identifier that
+ // was assumed to be an ADL-only function name
+ANNOTATION(non_type_dependent) // annotation for an assumed non-type member of
+ // a dependent base class
ANNOTATION(primary_expr) // annotation for a primary expression
ANNOTATION(decltype) // annotation for a decltype expression,
// e.g., "decltype(foo.bar())"
@@ -729,103 +740,103 @@ ANNOTATION(decltype) // annotation for a decltype expression,
// 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)
+PRAGMA_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)
+PRAGMA_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)
+PRAGMA_ANNOTATION(pragma_pack)
// Annotation for #pragma clang __debug parser_crash...
// The lexer produces these so that they only take effect when the parser
// handles them.
-ANNOTATION(pragma_parser_crash)
+PRAGMA_ANNOTATION(pragma_parser_crash)
// Annotation for #pragma clang __debug captured...
// The lexer produces these so that they only take effect when the parser
// handles them.
-ANNOTATION(pragma_captured)
+PRAGMA_ANNOTATION(pragma_captured)
// Annotation for #pragma clang __debug dump...
// The lexer produces these so that the parser and semantic analysis can
// look up and dump the operand.
-ANNOTATION(pragma_dump)
+PRAGMA_ANNOTATION(pragma_dump)
// Annotation for #pragma ms_struct...
// The lexer produces these so that they only take effect when the parser
// handles them.
-ANNOTATION(pragma_msstruct)
+PRAGMA_ANNOTATION(pragma_msstruct)
// Annotation for #pragma align...
// The lexer produces these so that they only take effect when the parser
// handles them.
-ANNOTATION(pragma_align)
+PRAGMA_ANNOTATION(pragma_align)
// Annotation for #pragma weak id
// The lexer produces these so that they only take effect when the parser
// handles them.
-ANNOTATION(pragma_weak)
+PRAGMA_ANNOTATION(pragma_weak)
// Annotation for #pragma weak id = id
// The lexer produces these so that they only take effect when the parser
// handles them.
-ANNOTATION(pragma_weakalias)
+PRAGMA_ANNOTATION(pragma_weakalias)
// Annotation for #pragma redefine_extname...
// The lexer produces these so that they only take effect when the parser
// handles them.
-ANNOTATION(pragma_redefine_extname)
+PRAGMA_ANNOTATION(pragma_redefine_extname)
// Annotation for #pragma STDC FP_CONTRACT...
// The lexer produces these so that they only take effect when the parser
// handles them.
-ANNOTATION(pragma_fp_contract)
+PRAGMA_ANNOTATION(pragma_fp_contract)
// Annotation for #pragma STDC FENV_ACCESS
// The lexer produces these so that they only take effect when the parser
// handles them.
-ANNOTATION(pragma_fenv_access)
+PRAGMA_ANNOTATION(pragma_fenv_access)
// Annotation for #pragma pointers_to_members...
// The lexer produces these so that they only take effect when the parser
// handles them.
-ANNOTATION(pragma_ms_pointers_to_members)
+PRAGMA_ANNOTATION(pragma_ms_pointers_to_members)
// Annotation for #pragma vtordisp...
// The lexer produces these so that they only take effect when the parser
// handles them.
-ANNOTATION(pragma_ms_vtordisp)
+PRAGMA_ANNOTATION(pragma_ms_vtordisp)
// Annotation for all microsoft #pragmas...
// The lexer produces these so that they only take effect when the parser
// handles them.
-ANNOTATION(pragma_ms_pragma)
+PRAGMA_ANNOTATION(pragma_ms_pragma)
// Annotation for #pragma OPENCL EXTENSION...
// The lexer produces these so that they only take effect when the parser
// handles them.
-ANNOTATION(pragma_opencl_extension)
+PRAGMA_ANNOTATION(pragma_opencl_extension)
// Annotations for OpenMP pragma directives - #pragma omp ...
// The lexer produces these so that they only take effect when the parser
// handles #pragma omp ... directives.
-ANNOTATION(pragma_openmp)
-ANNOTATION(pragma_openmp_end)
+PRAGMA_ANNOTATION(pragma_openmp)
+PRAGMA_ANNOTATION(pragma_openmp_end)
// Annotations for loop pragma directives #pragma clang loop ...
// The lexer produces these so that they only take effect when the parser
// handles #pragma loop ... directives.
-ANNOTATION(pragma_loop_hint)
+PRAGMA_ANNOTATION(pragma_loop_hint)
-ANNOTATION(pragma_fp)
+PRAGMA_ANNOTATION(pragma_fp)
// Annotation for the attribute pragma directives - #pragma clang attribute ...
-ANNOTATION(pragma_attribute)
+PRAGMA_ANNOTATION(pragma_attribute)
// Annotations for module import translated from #include etc.
ANNOTATION(module_include)
@@ -836,6 +847,7 @@ ANNOTATION(module_end)
// into the name of a header unit.
ANNOTATION(header_unit)
+#undef PRAGMA_ANNOTATION
#undef ANNOTATION
#undef TESTING_KEYWORD
#undef OBJC_AT_KEYWORD
diff --git a/include/clang/Basic/TokenKinds.h b/include/clang/Basic/TokenKinds.h
index 1d5be5f9152e..c25181e6827c 100644
--- a/include/clang/Basic/TokenKinds.h
+++ b/include/clang/Basic/TokenKinds.h
@@ -90,13 +90,10 @@ inline bool isLiteral(TokenKind K) {
}
/// Return true if this is any of tok::annot_* kinds.
-inline bool isAnnotation(TokenKind K) {
-#define ANNOTATION(NAME) \
- if (K == tok::annot_##NAME) \
- return true;
-#include "clang/Basic/TokenKinds.def"
- return false;
-}
+bool isAnnotation(TokenKind K);
+
+/// Return true if this is an annotation token representing a pragma.
+bool isPragmaAnnotation(TokenKind K);
} // end namespace tok
} // end namespace clang
diff --git a/include/clang/Basic/TypeNodes.td b/include/clang/Basic/TypeNodes.td
new file mode 100644
index 000000000000..b2554de24aaf
--- /dev/null
+++ b/include/clang/Basic/TypeNodes.td
@@ -0,0 +1,106 @@
+class Type<bit abstract = 0> {
+ bit Abstract = abstract;
+}
+
+class DerivedType<Type base, bit abstract = 0> : Type<abstract> {
+ Type Base = base;
+}
+
+/// A type node that is only used to represent dependent types in C++. For
+/// example, DependentTemplateSpecializationType is used to represent types
+/// where the base template-id is dependent (such as `T::foo<U>`). Code
+/// that only works with non-dependent types can ignore these type nodes.
+class AlwaysDependent {}
+
+/// A type node that is never used to represent a canonical type, which is to
+/// say that it always represents some sort of type "sugar" which can
+/// (supposedly) be erased without affecting the formal behavior of the
+/// language. For example, in standard C/C++, typedefs do not introduce new
+/// types and do not affect the semantics of the program. Code that only
+/// works with canonical types can ignore these type nodes.
+///
+/// Note that this simple story about non-canonical types is not the whole
+/// truth. Languages and extensions often have formation rules which differ
+/// based on how a type is spelled and which therefore are not consistent
+/// with immediately stipping away type sugar. More critically, attributes on
+/// typedefs can have semantic impacts in ways that are only reflected in our
+/// AST by preserving the typedef sugar; for example, we do not otherwise
+/// represent the alignment attribute on typedefs, and so it is necessary to
+/// preserve typedef structure into most parts of IR generation.
+class NeverCanonical {}
+
+/// A type node that only represents a canonical type in some dependent cases.
+/// For example, `std::vector<int>` (a TemplateSpecializationType) is
+/// considered to be a non-canonical representation for the RecordType
+/// referencing the concrete ClassTemplateSpecializationDecl; but
+/// `std::vector<T>` cannot be resolved to a concrete specialization
+/// and so remains canonical. Code which only works with non-dependent
+/// canonical types can ignore these nodes.
+class NeverCanonicalUnlessDependent {}
+
+/// A type node which never has component type structure. Some code may be
+/// able to operate on leaf types faster than they can on non-leaf types.
+///
+/// For example, the function type `void (int)` is not a leaf type because it
+/// is structurally composed of component types (`void` and `int`).
+///
+/// A struct type is a leaf type because its field types are not part of its
+/// type-expression.
+///
+/// Nodes like `TypedefType` which are syntactically leaves but can desugar
+/// to types that may not be leaves should not declare this.
+class LeafType {}
+
+def BuiltinType : Type, LeafType;
+def ComplexType : Type;
+def PointerType : Type;
+def BlockPointerType : Type;
+def ReferenceType : Type<1>;
+def LValueReferenceType : DerivedType<ReferenceType>;
+def RValueReferenceType : DerivedType<ReferenceType>;
+def MemberPointerType : Type;
+def ArrayType : Type<1>;
+def ConstantArrayType : DerivedType<ArrayType>;
+def IncompleteArrayType : DerivedType<ArrayType>;
+def VariableArrayType : DerivedType<ArrayType>;
+def DependentSizedArrayType : DerivedType<ArrayType>, AlwaysDependent;
+def DependentSizedExtVectorType : Type, AlwaysDependent;
+def DependentAddressSpaceType : Type, AlwaysDependent;
+def VectorType : Type;
+def DependentVectorType : Type, AlwaysDependent;
+def ExtVectorType : DerivedType<VectorType>;
+def FunctionType : Type<1>;
+def FunctionProtoType : DerivedType<FunctionType>;
+def FunctionNoProtoType : DerivedType<FunctionType>;
+def UnresolvedUsingType : Type, AlwaysDependent;
+def ParenType : Type, NeverCanonical;
+def TypedefType : Type, NeverCanonical;
+def MacroQualifiedType : Type, NeverCanonical;
+def AdjustedType : Type, NeverCanonical;
+def DecayedType : DerivedType<AdjustedType>, NeverCanonical;
+def TypeOfExprType : Type, NeverCanonicalUnlessDependent;
+def TypeOfType : Type, NeverCanonicalUnlessDependent;
+def DecltypeType : Type, NeverCanonicalUnlessDependent;
+def UnaryTransformType : Type, NeverCanonicalUnlessDependent;
+def TagType : Type<1>;
+def RecordType : DerivedType<TagType>, LeafType;
+def EnumType : DerivedType<TagType>, LeafType;
+def ElaboratedType : Type, NeverCanonical;
+def AttributedType : Type, NeverCanonical;
+def TemplateTypeParmType : Type, AlwaysDependent, LeafType;
+def SubstTemplateTypeParmType : Type, NeverCanonical;
+def SubstTemplateTypeParmPackType : Type, AlwaysDependent;
+def TemplateSpecializationType : Type, NeverCanonicalUnlessDependent;
+def DeducedType : Type<1>;
+def AutoType : DerivedType<DeducedType>;
+def DeducedTemplateSpecializationType : DerivedType<DeducedType>;
+def InjectedClassNameType : Type, AlwaysDependent, LeafType;
+def DependentNameType : Type, AlwaysDependent;
+def DependentTemplateSpecializationType : Type, AlwaysDependent;
+def PackExpansionType : Type, NeverCanonicalUnlessDependent;
+def ObjCTypeParamType : Type, NeverCanonical;
+def ObjCObjectType : Type;
+def ObjCInterfaceType : DerivedType<ObjCObjectType>, LeafType;
+def ObjCObjectPointerType : Type;
+def PipeType : Type;
+def AtomicType : Type;
diff --git a/include/clang/Basic/X86Target.def b/include/clang/Basic/X86Target.def
index 94ccb9fd8b2f..ba4e5981e7dc 100644
--- a/include/clang/Basic/X86Target.def
+++ b/include/clang/Basic/X86Target.def
@@ -173,6 +173,10 @@ PROC(IcelakeClient, "icelake-client", PROC_64_BIT)
/// Icelake server microarchitecture based processors.
PROC(IcelakeServer, "icelake-server", PROC_64_BIT)
+/// \name Tigerlake
+/// Tigerlake microarchitecture based processors.
+PROC(Tigerlake, "tigerlake", PROC_64_BIT)
+
/// \name Knights Landing
/// Knights Landing processor.
PROC_WITH_FEAT(KNL, "knl", PROC_64_BIT, FEATURE_AVX512F)
@@ -297,6 +301,7 @@ FEATURE(FEATURE_VPCLMULQDQ)
FEATURE(FEATURE_AVX512VNNI)
FEATURE(FEATURE_AVX512BITALG)
FEATURE(FEATURE_AVX512BF16)
+FEATURE(FEATURE_AVX512VP2INTERSECT)
// FIXME: When commented out features are supported in LLVM, enable them here.
diff --git a/include/clang/Basic/arm_neon.td b/include/clang/Basic/arm_neon.td
index 428c22d1a011..a52ed496580d 100644
--- a/include/clang/Basic/arm_neon.td
+++ b/include/clang/Basic/arm_neon.td
@@ -1651,10 +1651,10 @@ let ArchGuard = "defined(__ARM_FEATURE_DOTPROD) && defined(__aarch64__)" in {
// v8.2-A FP16 fused multiply-add long instructions.
let ArchGuard = "defined(__ARM_FEATURE_FP16FML) && defined(__aarch64__)" in {
- def VFMLAL_LOW : SInst<"vfmlal_low", "ffHH", "hQh">;
- def VFMLSL_LOW : SInst<"vfmlsl_low", "ffHH", "hQh">;
- def VFMLAL_HIGH : SInst<"vfmlal_high", "ffHH", "hQh">;
- def VFMLSL_HIGH : SInst<"vfmlsl_high", "ffHH", "hQh">;
+ def VFMLAL_LOW : SInst<"vfmlal_low", "nndd", "hQh">;
+ def VFMLSL_LOW : SInst<"vfmlsl_low", "nndd", "hQh">;
+ def VFMLAL_HIGH : SInst<"vfmlal_high", "nndd", "hQh">;
+ def VFMLSL_HIGH : SInst<"vfmlsl_high", "nndd", "hQh">;
def VFMLAL_LANE_LOW : SOpInst<"vfmlal_lane_low", "ffH0i", "hQh", OP_FMLAL_LN>;
def VFMLSL_LANE_LOW : SOpInst<"vfmlsl_lane_low", "ffH0i", "hQh", OP_FMLSL_LN>;
diff --git a/include/clang/CodeGen/CGFunctionInfo.h b/include/clang/CodeGen/CGFunctionInfo.h
index 1f81072e23d0..5069d9af42a3 100644
--- a/include/clang/CodeGen/CGFunctionInfo.h
+++ b/include/clang/CodeGen/CGFunctionInfo.h
@@ -109,14 +109,12 @@ private:
UnpaddedCoerceAndExpandType = T;
}
- ABIArgInfo(Kind K)
- : TheKind(K), PaddingInReg(false), InReg(false) {
- }
-
public:
- ABIArgInfo()
+ ABIArgInfo(Kind K = Direct)
: TypeData(nullptr), PaddingType(nullptr), DirectOffset(0),
- TheKind(Direct), PaddingInReg(false), InReg(false) {}
+ TheKind(K), PaddingInReg(false), InAllocaSRet(false),
+ IndirectByVal(false), IndirectRealign(false), SRetAfterThis(false),
+ InReg(false), CanBeFlattened(false), SignExt(false) {}
static ABIArgInfo getDirect(llvm::Type *T = nullptr, unsigned Offset = 0,
llvm::Type *Padding = nullptr,
diff --git a/include/clang/CrossTU/CrossTranslationUnit.h b/include/clang/CrossTU/CrossTranslationUnit.h
index d64329cdff3e..4d2b7109c62a 100644
--- a/include/clang/CrossTU/CrossTranslationUnit.h
+++ b/include/clang/CrossTU/CrossTranslationUnit.h
@@ -17,6 +17,7 @@
#include "clang/AST/ASTImporterSharedState.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/Error.h"
@@ -153,18 +154,34 @@ public:
/// was passed to the constructor.
///
/// \return Returns the resulting definition or an error.
- llvm::Expected<const FunctionDecl *> importDefinition(const FunctionDecl *FD);
- llvm::Expected<const VarDecl *> importDefinition(const VarDecl *VD);
+ llvm::Expected<const FunctionDecl *> importDefinition(const FunctionDecl *FD,
+ ASTUnit *Unit);
+ llvm::Expected<const VarDecl *> importDefinition(const VarDecl *VD,
+ ASTUnit *Unit);
/// Get a name to identify a named decl.
- static std::string getLookupName(const NamedDecl *ND);
+ static llvm::Optional<std::string> getLookupName(const NamedDecl *ND);
/// Emit diagnostics for the user for potential configuration errors.
void emitCrossTUDiagnostics(const IndexError &IE);
+ /// Determine the original source location in the original TU for an
+ /// imported source location.
+ /// \p ToLoc Source location in the imported-to AST.
+ /// \return Source location in the imported-from AST and the corresponding
+ /// ASTUnit object (the AST was loaded from a file using an internal ASTUnit
+ /// object that is returned here).
+ /// If any error happens (ToLoc is a non-imported source location) empty is
+ /// returned.
+ llvm::Optional<std::pair<SourceLocation /*FromLoc*/, ASTUnit *>>
+ getImportedFromSourceLocation(const clang::SourceLocation &ToLoc) const;
+
private:
+ using ImportedFileIDMap =
+ llvm::DenseMap<FileID, std::pair<FileID, ASTUnit *>>;
+
void lazyInitImporterSharedSt(TranslationUnitDecl *ToTU);
- ASTImporter &getOrCreateASTImporter(ASTContext &From);
+ ASTImporter &getOrCreateASTImporter(ASTUnit *Unit);
template <typename T>
llvm::Expected<const T *> getCrossTUDefinitionImpl(const T *D,
StringRef CrossTUDir,
@@ -174,20 +191,114 @@ private:
const T *findDefInDeclContext(const DeclContext *DC,
StringRef LookupName);
template <typename T>
- llvm::Expected<const T *> importDefinitionImpl(const T *D);
-
- llvm::StringMap<std::unique_ptr<clang::ASTUnit>> FileASTUnitMap;
- llvm::StringMap<clang::ASTUnit *> NameASTUnitMap;
- llvm::StringMap<std::string> NameFileMap;
- llvm::DenseMap<TranslationUnitDecl *, std::unique_ptr<ASTImporter>>
- ASTUnitImporterMap;
- CompilerInstance &CI;
+ llvm::Expected<const T *> importDefinitionImpl(const T *D, ASTUnit *Unit);
+
+ using ImporterMapTy =
+ llvm::DenseMap<TranslationUnitDecl *, std::unique_ptr<ASTImporter>>;
+
+ ImporterMapTy ASTUnitImporterMap;
+
ASTContext &Context;
std::shared_ptr<ASTImporterSharedState> ImporterSharedSt;
- /// \p CTULoadTreshold should serve as an upper limit to the number of TUs
- /// imported in order to reduce the memory footprint of CTU analysis.
- const unsigned CTULoadThreshold;
- unsigned NumASTLoaded{0u};
+ /// Map of imported FileID's (in "To" context) to FileID in "From" context
+ /// and the ASTUnit for the From context.
+ /// This map is used by getImportedFromSourceLocation to lookup a FileID and
+ /// its Preprocessor when knowing only the FileID in the 'To' context. The
+ /// FileID could be imported by any of multiple 'From' ASTImporter objects.
+ /// we do not want to loop over all ASTImporter's to find the one that
+ /// imported the FileID.
+ ImportedFileIDMap ImportedFileIDs;
+
+ /// Functor for loading ASTUnits from AST-dump files.
+ class ASTFileLoader {
+ public:
+ ASTFileLoader(const CompilerInstance &CI);
+ std::unique_ptr<ASTUnit> operator()(StringRef ASTFilePath);
+
+ private:
+ const CompilerInstance &CI;
+ };
+
+ /// Maintain number of AST loads and check for reaching the load limit.
+ class ASTLoadGuard {
+ public:
+ ASTLoadGuard(unsigned Limit) : Limit(Limit) {}
+
+ /// Indicates, whether a new load operation is permitted, it is within the
+ /// threshold.
+ operator bool() const { return Count < Limit; }
+
+ /// Tell that a new AST was loaded successfully.
+ void indicateLoadSuccess() { ++Count; }
+
+ private:
+ /// The number of ASTs actually imported.
+ unsigned Count{0u};
+ /// The limit (threshold) value for number of loaded ASTs.
+ const unsigned Limit;
+ };
+
+ /// Storage and load of ASTUnits, cached access, and providing searchability
+ /// are the concerns of ASTUnitStorage class.
+ class ASTUnitStorage {
+ public:
+ ASTUnitStorage(const CompilerInstance &CI);
+ /// Loads an ASTUnit for a function.
+ ///
+ /// \param FunctionName USR name of the function.
+ /// \param CrossTUDir Path to the directory used to store CTU related files.
+ /// \param IndexName Name of the file inside \p CrossTUDir which maps
+ /// function USR names to file paths. These files contain the corresponding
+ /// AST-dumps.
+ /// \param DisplayCTUProgress Display a message about loading new ASTs.
+ ///
+ /// \return An Expected instance which contains the ASTUnit pointer or the
+ /// error occured during the load.
+ llvm::Expected<ASTUnit *> getASTUnitForFunction(StringRef FunctionName,
+ StringRef CrossTUDir,
+ StringRef IndexName,
+ bool DisplayCTUProgress);
+ /// Identifies the path of the file which can be used to load the ASTUnit
+ /// for a given function.
+ ///
+ /// \param FunctionName USR name of the function.
+ /// \param CrossTUDir Path to the directory used to store CTU related files.
+ /// \param IndexName Name of the file inside \p CrossTUDir which maps
+ /// function USR names to file paths. These files contain the corresponding
+ /// AST-dumps.
+ ///
+ /// \return An Expected instance containing the filepath.
+ llvm::Expected<std::string> getFileForFunction(StringRef FunctionName,
+ StringRef CrossTUDir,
+ StringRef IndexName);
+
+ private:
+ llvm::Error ensureCTUIndexLoaded(StringRef CrossTUDir, StringRef IndexName);
+ llvm::Expected<ASTUnit *> getASTUnitForFile(StringRef FileName,
+ bool DisplayCTUProgress);
+
+ template <typename... T> using BaseMapTy = llvm::StringMap<T...>;
+ using OwningMapTy = BaseMapTy<std::unique_ptr<clang::ASTUnit>>;
+ using NonOwningMapTy = BaseMapTy<clang::ASTUnit *>;
+
+ OwningMapTy FileASTUnitMap;
+ NonOwningMapTy NameASTUnitMap;
+
+ using IndexMapTy = BaseMapTy<std::string>;
+ IndexMapTy NameFileMap;
+
+ ASTFileLoader FileAccessor;
+
+ /// Limit the number of loaded ASTs. Used to limit the memory usage of the
+ /// CrossTranslationUnitContext.
+ /// The ASTUnitStorage has the knowledge about if the AST to load is
+ /// actually loaded or returned from cache. This information is needed to
+ /// maintain the counter.
+ ASTLoadGuard LoadGuard;
+ };
+
+ ASTUnitStorage ASTStorage;
+
};
} // namespace cross_tu
diff --git a/include/clang/DirectoryWatcher/DirectoryWatcher.h b/include/clang/DirectoryWatcher/DirectoryWatcher.h
index e74443e0bc81..4475807dfce9 100644
--- a/include/clang/DirectoryWatcher/DirectoryWatcher.h
+++ b/include/clang/DirectoryWatcher/DirectoryWatcher.h
@@ -11,6 +11,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
#include <functional>
#include <memory>
#include <string>
@@ -98,10 +99,11 @@ public:
: Kind(Kind), Filename(Filename) {}
};
- /// Returns nullptr if \param Path doesn't exist or isn't a directory.
- /// Returns nullptr if OS kernel API told us we can't start watching. In such
- /// case it's unclear whether just retrying has any chance to succeeed.
- static std::unique_ptr<DirectoryWatcher>
+ /// llvm fatal_error if \param Path doesn't exist or isn't a directory.
+ /// Returns llvm::Expected Error if OS kernel API told us we can't start
+ /// watching. In such case it's unclear whether just retrying has any chance
+ /// to succeed.
+ static llvm::Expected<std::unique_ptr<DirectoryWatcher>>
create(llvm::StringRef Path,
std::function<void(llvm::ArrayRef<DirectoryWatcher::Event> Events,
bool IsInitial)>
diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h
index c1ff0b1a6023..8ccbb6c2bbfa 100644
--- a/include/clang/Driver/Action.h
+++ b/include/clang/Driver/Action.h
@@ -65,15 +65,17 @@ public:
BackendJobClass,
AssembleJobClass,
LinkJobClass,
+ IfsMergeJobClass,
LipoJobClass,
DsymutilJobClass,
VerifyDebugInfoJobClass,
VerifyPCHJobClass,
OffloadBundlingJobClass,
OffloadUnbundlingJobClass,
+ OffloadWrapperJobClass,
JobClassFirst = PreprocessJobClass,
- JobClassLast = OffloadUnbundlingJobClass
+ JobClassLast = OffloadWrapperJobClass
};
// The offloading kind determines if this action is binded to a particular
@@ -485,6 +487,17 @@ public:
}
};
+class IfsMergeJobAction : public JobAction {
+ void anchor() override;
+
+public:
+ IfsMergeJobAction(ActionList &Inputs, types::ID Type);
+
+ static bool classof(const Action *A) {
+ return A->getKind() == IfsMergeJobClass;
+ }
+};
+
class LinkJobAction : public JobAction {
void anchor() override;
@@ -613,6 +626,17 @@ public:
}
};
+class OffloadWrapperJobAction : public JobAction {
+ void anchor() override;
+
+public:
+ OffloadWrapperJobAction(ActionList &Inputs, types::ID Type);
+
+ static bool classof(const Action *A) {
+ return A->getKind() == OffloadWrapperJobClass;
+ }
+};
+
} // namespace driver
} // namespace clang
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 1f6c000ecf6a..4518aca82ef6 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -140,7 +140,8 @@ def analyzer_checker_help_developer : Flag<["-"], "analyzer-checker-help-develop
"and debug checkers">;
def analyzer_config_help : Flag<["-"], "analyzer-config-help">,
- HelpText<"Display the list of -analyzer-config options">;
+ HelpText<"Display the list of -analyzer-config options. These are meant for "
+ "development purposes only!">;
def analyzer_list_enabled_checkers : Flag<["-"], "analyzer-list-enabled-checkers">,
HelpText<"Display the list of enabled analyzer checkers">;
@@ -200,6 +201,8 @@ def compress_debug_sections_EQ : Joined<["-", "--"], "compress-debug-sections=">
HelpText<"DWARF debug sections compression type">;
def mno_exec_stack : Flag<["-"], "mnoexecstack">,
HelpText<"Mark the file as not needing an executable stack">;
+def massembler_no_warn : Flag<["-"], "massembler-no-warn">,
+ HelpText<"Make assembler not emit warnings">;
def massembler_fatal_warnings : Flag<["-"], "massembler-fatal-warnings">,
HelpText<"Make assembler warnings fatal">;
def mrelax_relocations : Flag<["--"], "mrelax-relocations">,
@@ -285,8 +288,8 @@ def mcode_model : Separate<["-"], "mcode-model">,
HelpText<"The code model to use">, Values<"tiny,small,kernel,medium,large">;
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 mframe_pointer_EQ : Joined<["-"], "mframe-pointer=">,
+ HelpText<"Specify which frame pointers to retain (all, non-leaf, none).">, Values<"all,non-leaf,none">;
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">,
@@ -684,7 +687,7 @@ let Flags = [CC1Option, CC1AsOption, NoDriverOption] in {
def version : Flag<["-"], "version">,
HelpText<"Print the compiler version">;
def main_file_name : Separate<["-"], "main-file-name">,
- HelpText<"Main file name to use for debug info">;
+ HelpText<"Main file name to use for debug info and source if missing">;
def split_dwarf_output : Separate<["-"], "split-dwarf-output">,
HelpText<"File name to use for split dwarf debug info output">;
@@ -812,6 +815,9 @@ def fdisable_module_hash : Flag<["-"], "fdisable-module-hash">,
HelpText<"Disable the module hash">;
def fmodules_hash_content : Flag<["-"], "fmodules-hash-content">,
HelpText<"Enable hashing the content of a module file">;
+def fmodules_strict_context_hash : Flag<["-"], "fmodules-strict-context-hash">,
+ HelpText<"Enable hashing of all compiler options that could impact the "
+ "semantics of a module in an implicit build">;
def c_isystem : JoinedOrSeparate<["-"], "c-isystem">, MetaVarName<"<directory>">,
HelpText<"Add directory to the C SYSTEM include search path">;
def objc_isystem : JoinedOrSeparate<["-"], "objc-isystem">,
@@ -843,6 +849,8 @@ def preamble_bytes_EQ : Joined<["-"], "preamble-bytes=">,
"covering the first N bytes of the main file">;
def detailed_preprocessing_record : Flag<["-"], "detailed-preprocessing-record">,
HelpText<"include a detailed record of preprocessing actions">;
+def setup_static_analyzer : Flag<["-"], "setup-static-analyzer">,
+ HelpText<"Set up preprocessor for static analyzer (done automatically when static analyzer is run).">;
//===----------------------------------------------------------------------===//
// OpenCL Options
diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td
index a0af3035ea46..50d4622009c9 100644
--- a/include/clang/Driver/CLCompatOptions.td
+++ b/include/clang/Driver/CLCompatOptions.td
@@ -254,7 +254,13 @@ def _SLASH_Zp_flag : CLFlag<"Zp">,
Alias<fpack_struct_EQ>, AliasArgs<["1"]>;
def _SLASH_Zs : CLFlag<"Zs">, HelpText<"Syntax-check only">,
Alias<fsyntax_only>;
-
+def _SLASH_openmp_ : CLFlag<"openmp-">,
+ HelpText<"Disable OpenMP support">, Alias<fno_openmp>;
+def _SLASH_openmp : CLFlag<"openmp">, HelpText<"Enable OpenMP support">,
+ Alias<fopenmp>;
+def _SLASH_openmp_experimental : CLFlag<"openmp:experimental">,
+ HelpText<"Enable OpenMP support with experimental SIMD support">,
+ Alias<fopenmp>;
// Non-aliases:
@@ -381,7 +387,6 @@ def _SLASH_FS : CLIgnoredFlag<"FS">;
def _SLASH_JMC : CLIgnoredFlag<"JMC">;
def _SLASH_kernel_ : CLIgnoredFlag<"kernel-">;
def _SLASH_nologo : CLIgnoredFlag<"nologo">;
-def _SLASH_openmp_ : CLIgnoredFlag<"openmp-">;
def _SLASH_permissive_ : CLIgnoredFlag<"permissive-">;
def _SLASH_RTC : CLIgnoredJoined<"RTC">;
def _SLASH_sdl : CLIgnoredFlag<"sdl">;
@@ -396,6 +401,9 @@ def _SLASH_Zc_inline : CLIgnoredFlag<"Zc:inline">;
def _SLASH_Zc_rvalueCast : CLIgnoredFlag<"Zc:rvalueCast">;
def _SLASH_Zc_ternary : CLIgnoredFlag<"Zc:ternary">;
def _SLASH_Zc_wchar_t : CLIgnoredFlag<"Zc:wchar_t">;
+def _SLASH_ZH_MD5 : CLIgnoredFlag<"ZH:MD5">;
+def _SLASH_ZH_SHA1 : CLIgnoredFlag<"ZH:SHA1">;
+def _SLASH_ZH_SHA_256 : CLIgnoredFlag<"ZH:SHA_256">;
def _SLASH_Zm : CLIgnoredJoined<"Zm">;
def _SLASH_Zo : CLIgnoredFlag<"Zo">;
def _SLASH_Zo_ : CLIgnoredFlag<"Zo-">;
@@ -436,8 +444,6 @@ def _SLASH_hotpatch : CLFlag<"hotpatch">;
def _SLASH_kernel : CLFlag<"kernel">;
def _SLASH_LN : CLFlag<"LN">;
def _SLASH_MP : CLJoined<"MP">;
-def _SLASH_openmp : CLFlag<"openmp">;
-def _SLASH_openmp_experimental : CLFlag<"openmp:experimental">;
def _SLASH_Qfast_transcendentals : CLFlag<"Qfast_transcendentals">;
def _SLASH_QIfist : CLFlag<"QIfist">;
def _SLASH_Qimprecise_fwaits : CLFlag<"Qimprecise_fwaits">;
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index f9528641073a..5e7283e31ee0 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -12,12 +12,14 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LLVM.h"
#include "clang/Driver/Action.h"
+#include "clang/Driver/Options.h"
#include "clang/Driver/Phases.h"
#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Types.h"
#include "clang/Driver/Util.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/StringSaver.h"
@@ -55,8 +57,6 @@ enum LTOKind {
/// Driver - Encapsulate logic for constructing compilation processes
/// from a set of gcc-driver-like command line arguments.
class Driver {
- std::unique_ptr<llvm::opt::OptTable> Opts;
-
DiagnosticsEngine &Diags;
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS;
@@ -250,9 +250,17 @@ private:
// getFinalPhase - Determine which compilation mode we are in and record
// which option we used to determine the final phase.
+ // TODO: Much of what getFinalPhase returns are not actually true compiler
+ // modes. Fold this functionality into Types::getCompilationPhases and
+ // handleArguments.
phases::ID getFinalPhase(const llvm::opt::DerivedArgList &DAL,
llvm::opt::Arg **FinalPhaseArg = nullptr) const;
+ // handleArguments - All code related to claiming and printing diagnostics
+ // related to arguments to the driver are done here.
+ void handleArguments(Compilation &C, llvm::opt::DerivedArgList &Args,
+ const InputList &Inputs, ActionList &Actions) const;
+
// Before executing jobs, sets up response files for commands that need them.
void setUpResponseFiles(Compilation &C, Command &Cmd);
@@ -292,7 +300,7 @@ public:
const std::string &getConfigFile() const { return ConfigFile; }
- const llvm::opt::OptTable &getOpts() const { return *Opts; }
+ const llvm::opt::OptTable &getOpts() const { return getDriverOptTable(); }
const DiagnosticsEngine &getDiags() const { return Diags; }
diff --git a/include/clang/Driver/Options.h b/include/clang/Driver/Options.h
index f8963d48112a..7c5cddd9e896 100644
--- a/include/clang/Driver/Options.h
+++ b/include/clang/Driver/Options.h
@@ -47,7 +47,7 @@ enum ID {
};
}
-std::unique_ptr<llvm::opt::OptTable> createDriverOptTable();
+const llvm::opt::OptTable &getDriverOptTable();
}
}
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index dfd27fab796e..3ce6fcf29f94 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -211,6 +211,10 @@ def clang_ignored_legacy_options_Group : OptionGroup<"<clang legacy flags>">,
def : Flag<["-"], "fslp-vectorize-aggressive">, Group<clang_ignored_legacy_options_Group>;
def : Flag<["-"], "fno-slp-vectorize-aggressive">, Group<clang_ignored_legacy_options_Group>;
+// Retired with clang-10.0. Previously controlled X86 MPX ISA.
+def mmpx : Flag<["-"], "mmpx">, Group<clang_ignored_legacy_options_Group>;
+def mno_mpx : Flag<["-"], "mno-mpx">, Group<clang_ignored_legacy_options_Group>;
+
// Group that ignores all gcc optimizations that won't be implemented
def clang_ignored_gcc_optimization_f_Group : OptionGroup<
"<clang_ignored_gcc_optimization_f_Group>">, Group<f_Group>, Flags<[Ignored]>;
@@ -280,6 +284,8 @@ def arcmt_migrate_emit_arc_errors : Flag<["-"], "arcmt-migrate-emit-errors">,
Flags<[CC1Option]>;
def gen_reproducer: Flag<["-"], "gen-reproducer">, InternalDebugOpt,
HelpText<"Auto-generates preprocessed source files and a reproduction script">;
+def gen_cdb_fragment_path: Separate<["-"], "gen-cdb-fragment-path">, InternalDebugOpt,
+ HelpText<"Emit a compilation database fragment to the specified directory">;
def _migrate : Flag<["--"], "migrate">, Flags<[DriverOption]>,
HelpText<"Run the migrator">;
@@ -518,7 +524,7 @@ def cl_mad_enable : Flag<["-"], "cl-mad-enable">, Group<opencl_Group>, Flags<[CC
def cl_no_signed_zeros : Flag<["-"], "cl-no-signed-zeros">, Group<opencl_Group>, Flags<[CC1Option]>,
HelpText<"OpenCL only. Allow use of less precise no signed zeros computations in the generated binary.">;
def cl_std_EQ : Joined<["-"], "cl-std=">, Group<opencl_Group>, Flags<[CC1Option]>,
- HelpText<"OpenCL language standard to compile for.">, Values<"cl,CL,cl1.1,CL1.1,cl1.2,CL1.2,cl2.0,CL2.0,c++">;
+ HelpText<"OpenCL language standard to compile for.">, Values<"cl,CL,cl1.1,CL1.1,cl1.2,CL1.2,cl2.0,CL2.0,clc++,CLC++">;
def cl_denorms_are_zero : Flag<["-"], "cl-denorms-are-zero">, Group<opencl_Group>, Flags<[CC1Option]>,
HelpText<"OpenCL only. Allow denormals to be flushed to zero.">;
def cl_fp32_correctly_rounded_divide_sqrt : Flag<["-"], "cl-fp32-correctly-rounded-divide-sqrt">, Group<opencl_Group>, Flags<[CC1Option]>,
@@ -593,9 +599,11 @@ def hip_device_lib_EQ : Joined<["--"], "hip-device-lib=">, Group<Link_Group>,
HelpText<"HIP device library">;
def fhip_dump_offload_linker_script : Flag<["-"], "fhip-dump-offload-linker-script">,
Group<f_Group>, Flags<[NoArgumentUnused, HelpHidden]>;
+def fhip_new_launch_api : Flag<["-"], "fhip-new-launch-api">,
+ Flags<[CC1Option]>, HelpText<"Use new kernel launching API for HIP.">;
+def fno_hip_new_launch_api : Flag<["-"], "fno-hip-new-launch-api">;
def libomptarget_nvptx_path_EQ : Joined<["--"], "libomptarget-nvptx-path=">, Group<i_Group>,
HelpText<"Path to libomptarget-nvptx libraries">;
-def dA : Flag<["-"], "dA">, Group<d_Group>;
def dD : Flag<["-"], "dD">, Group<d_Group>, Flags<[CC1Option]>,
HelpText<"Print macro definitions in -E mode in addition to normal output">;
def dI : Flag<["-"], "dI">, Group<d_Group>, Flags<[CC1Option]>,
@@ -623,9 +631,12 @@ def emit_ast : Flag<["-"], "emit-ast">,
HelpText<"Emit Clang AST files for source inputs">;
def emit_llvm : Flag<["-"], "emit-llvm">, Flags<[CC1Option]>, Group<Action_Group>,
HelpText<"Use the LLVM representation for assembler and object files">;
-def emit_iterface_stubs : Flag<["-"], "emit-interface-stubs">, Flags<[CC1Option]>, Group<Action_Group>,
+def emit_interface_stubs : Flag<["-"], "emit-interface-stubs">, Flags<[CC1Option]>, Group<Action_Group>,
HelpText<"Generate Inteface Stub Files.">;
-def iterface_stub_version_EQ : JoinedOrSeparate<["-"], "interface-stub-version=">, Flags<[CC1Option]>;
+def emit_merged_ifs : Flag<["-"], "emit-merged-ifs">,
+ Flags<[CC1Option]>, Group<Action_Group>,
+ HelpText<"Generate Interface Stub Files, emit merged text not binary.">;
+def interface_stub_version_EQ : JoinedOrSeparate<["-"], "interface-stub-version=">, Flags<[CC1Option]>;
def exported__symbols__list : Separate<["-"], "exported_symbols_list">;
def e : JoinedOrSeparate<["-"], "e">, Group<Link_Group>;
def fPIC : Flag<["-"], "fPIC">, Group<f_Group>;
@@ -833,6 +844,10 @@ 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_steps_EQ : Joined<["-"], "fconstexpr-steps=">, Group<f_Group>;
+def fexperimental_new_constant_interpreter : Flag<["-"], "fexperimental-new-constant-interpreter">, Group<f_Group>,
+ HelpText<"Enable the experimental new constant interpreter">, Flags<[CC1Option]>;
+def fforce_experimental_new_constant_interpreter : Flag<["-"], "fforce-experimental-new-constant-interpreter">, Group<f_Group>,
+ HelpText<"Force the use of the experimental new constant interpreter, failing on missing features">, Flags<[CC1Option]>;
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, CoreOption]>,
@@ -899,6 +914,8 @@ def fsjlj_exceptions : Flag<["-"], "fsjlj-exceptions">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Use SjLj style exceptions">;
def fseh_exceptions : Flag<["-"], "fseh-exceptions">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Use SEH style exceptions">;
+def fwasm_exceptions : Flag<["-"], "fwasm-exceptions">, Group<f_Group>,
+ Flags<[CC1Option]>, HelpText<"Use WebAssembly style exceptions">;
def fexcess_precision_EQ : Joined<["-"], "fexcess-precision=">,
Group<clang_ignored_gcc_optimization_f_Group>;
def : Flag<["-"], "fexpensive-optimizations">, Group<clang_ignored_gcc_optimization_f_Group>;
@@ -1043,8 +1060,14 @@ def fsanitize_minimal_runtime : Flag<["-"], "fsanitize-minimal-runtime">,
Group<f_clang_Group>;
def fno_sanitize_minimal_runtime : Flag<["-"], "fno-sanitize-minimal-runtime">,
Group<f_clang_Group>;
+def fsanitize_link_runtime : Flag<["-"], "fsanitize-link-runtime">,
+ Group<f_clang_Group>;
+def fno_sanitize_link_runtime : Flag<["-"], "fno-sanitize-link-runtime">,
+ Group<f_clang_Group>;
def fsanitize_link_cxx_runtime : Flag<["-"], "fsanitize-link-c++-runtime">,
Group<f_clang_Group>;
+def fno_sanitize_link_cxx_runtime : Flag<["-"], "fno-sanitize-link-c++-runtime">,
+ Group<f_clang_Group>;
def fsanitize_cfi_cross_dso : Flag<["-"], "fsanitize-cfi-cross-dso">,
Group<f_clang_Group>,
HelpText<"Enable control flow integrity (CFI) checks for cross-DSO calls.">;
@@ -1055,6 +1078,13 @@ def fno_sanitize_cfi_cross_dso : Flag<["-"], "fno-sanitize-cfi-cross-dso">,
def fsanitize_cfi_icall_generalize_pointers : Flag<["-"], "fsanitize-cfi-icall-generalize-pointers">,
Group<f_clang_Group>,
HelpText<"Generalize pointers in CFI indirect call type signature checks">;
+def fsanitize_cfi_canonical_jump_tables : Flag<["-"], "fsanitize-cfi-canonical-jump-tables">,
+ Group<f_clang_Group>,
+ HelpText<"Make the jump table addresses canonical in the symbol table">;
+def fno_sanitize_cfi_canonical_jump_tables : Flag<["-"], "fno-sanitize-cfi-canonical-jump-tables">,
+ Group<f_clang_Group>,
+ Flags<[CoreOption, DriverOption]>,
+ HelpText<"Do not make the jump table addresses canonical in the symbol table">;
def fsanitize_stats : Flag<["-"], "fsanitize-stats">,
Group<f_clang_Group>,
HelpText<"Enable sanitizer statistics gathering.">;
@@ -1117,7 +1147,8 @@ def ftrapping_math : Flag<["-"], "ftrapping-math">, Group<f_Group>, Flags<[CC1Op
def fno_trapping_math : Flag<["-"], "fno-trapping-math">, Group<f_Group>, Flags<[CC1Option]>;
def ffp_contract : Joined<["-"], "ffp-contract=">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Form fused FP ops (e.g. FMAs): fast (everywhere)"
- " | on (according to FP_CONTRACT pragma, default) | off (never fuse)">, Values<"fast,on,off">;
+ " | on (according to FP_CONTRACT pragma) | off (never fuse). Default"
+ " is 'fast' for CUDA/HIP and 'on' otherwise.">, Values<"fast,on,off">;
def fstrict_float_cast_overflow : Flag<["-"],
"fstrict-float-cast-overflow">, Group<f_Group>, Flags<[CC1Option]>,
@@ -1157,6 +1188,9 @@ def fno_use_line_directives : Flag<["-"], "fno-use-line-directives">, Group<f_Gr
def ffreestanding : Flag<["-"], "ffreestanding">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Assert that the compilation takes place in a freestanding environment">;
+def fgnuc_version_EQ : Joined<["-"], "fgnuc-version=">, Group<f_Group>,
+ HelpText<"Sets various macros to claim compatibility with the given GCC version (default is 4.2.1)">,
+ Flags<[CC1Option, CoreOption]>;
def fgnu_keywords : Flag<["-"], "fgnu-keywords">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Allow GNU-extension keywords regardless of language standard">;
def fgnu89_inline : Flag<["-"], "fgnu89-inline">, Group<f_Group>, Flags<[CC1Option]>,
@@ -1254,7 +1288,10 @@ def fno_fine_grained_bitfield_accesses : Flag<["-"],
HelpText<"Use large-integer access for consecutive bitfield runs.">;
def flat__namespace : Flag<["-"], "flat_namespace">;
-def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>;
+def flax_vector_conversions_EQ : Joined<["-"], "flax-vector-conversions=">, Group<f_Group>,
+ HelpText<"Enable implicit vector bit-casts">, Values<"none,integer,all">, Flags<[CC1Option]>;
+def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group<f_Group>,
+ Alias<flax_vector_conversions_EQ>, AliasArgs<["integer"]>;
def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group<f_Group>;
def fapple_link_rtlib : Flag<["-"], "fapple-link-rtlib">, Group<f_Group>,
HelpText<"Force linking the clang builtins runtime library">;
@@ -1331,6 +1368,28 @@ def fmodules_validate_system_headers : Flag<["-"], "fmodules-validate-system-hea
HelpText<"Validate the system headers that a module depends on when loading the module">;
def fno_modules_validate_system_headers : Flag<["-"], "fno-modules-validate-system-headers">,
Group<i_Group>, Flags<[DriverOption]>;
+
+def fvalidate_ast_input_files_content:
+ Flag <["-"], "fvalidate-ast-input-files-content">,
+ Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Compute and store the hash of input files used to build an AST."
+ " Files with mismatching mtime's are considered valid"
+ " if both contents is identical">;
+def fmodules_validate_input_files_content:
+ Flag <["-"], "fmodules-validate-input-files-content">,
+ Group<f_Group>, Flags<[DriverOption]>,
+ HelpText<"Validate PCM input files based on content if mtime differs">;
+def fno_modules_validate_input_files_content:
+ Flag <["-"], "fno_modules-validate-input-files-content">,
+ Group<f_Group>, Flags<[DriverOption]>;
+def fpch_validate_input_files_content:
+ Flag <["-"], "fpch-validate-input-files-content">,
+ Group<f_Group>, Flags<[DriverOption]>,
+ HelpText<"Validate PCH input files based on content if mtime differs">;
+def fno_pch_validate_input_files_content:
+ Flag <["-"], "fno_pch-validate-input-files-content">,
+ Group<f_Group>, Flags<[DriverOption]>;
+
def fmodules : Flag <["-"], "fmodules">, Group<f_Group>,
Flags<[DriverOption, CC1Option]>,
HelpText<"Enable the 'modules' language feature">;
@@ -1428,7 +1487,7 @@ def fno_experimental_new_pass_manager : Flag<["-"], "fno-experimental-new-pass-m
def fveclib : Joined<["-"], "fveclib=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Use the given vector functions library">, Values<"Accelerate,MASSV,SVML,none">;
def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group<f_Group>,
- HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">, Flags<[CC1Option]>;
+ Alias<flax_vector_conversions_EQ>, AliasArgs<["none"]>;
def fno_merge_all_constants : Flag<["-"], "fno-merge-all-constants">, Group<f_Group>,
HelpText<"Disallow merging of constants">;
def fno_modules : Flag <["-"], "fno-modules">, Group<f_Group>,
@@ -1571,8 +1630,6 @@ def fnoopenmp_use_tls : Flag<["-"], "fnoopenmp-use-tls">, Group<f_Group>,
Flags<[CC1Option, NoArgumentUnused, HelpHidden]>;
def fopenmp_targets_EQ : CommaJoined<["-"], "fopenmp-targets=">, Flags<[DriverOption, CC1Option]>,
HelpText<"Specify comma-separated list of triples OpenMP offloading targets to be supported">;
-def fopenmp_dump_offload_linker_script : Flag<["-"], "fopenmp-dump-offload-linker-script">,
- Group<f_Group>, Flags<[NoArgumentUnused, HelpHidden]>;
def fopenmp_relocatable_target : Flag<["-"], "fopenmp-relocatable-target">,
Group<f_Group>, Flags<[CC1Option, NoArgumentUnused, HelpHidden]>;
def fnoopenmp_relocatable_target : Flag<["-"], "fnoopenmp-relocatable-target">,
@@ -1598,6 +1655,8 @@ def fopenmp_optimistic_collapse : Flag<["-"], "fopenmp-optimistic-collapse">, Gr
Flags<[CC1Option, NoArgumentUnused, HelpHidden]>;
def fno_openmp_optimistic_collapse : Flag<["-"], "fno-openmp-optimistic-collapse">, Group<f_Group>,
Flags<[NoArgumentUnused, HelpHidden]>;
+def static_openmp: Flag<["-"], "static-openmp">,
+ HelpText<"Use the static host OpenMP runtime while linking.">;
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 fno_escaping_block_tail_calls : Flag<["-"], "fno-escaping-block-tail-calls">, Group<f_Group>, Flags<[CC1Option]>;
@@ -1683,10 +1742,10 @@ def fstack_protector : Flag<["-"], "fstack-protector">, Group<f_Group>,
"alloca, which are of greater size than ssp-buffer-size (default: 8 bytes). "
"All variable sized calls to alloca are considered vulnerable">;
def ftrivial_auto_var_init : Joined<["-"], "ftrivial-auto-var-init=">, Group<f_Group>,
- Flags<[CC1Option]>, HelpText<"Initialize trivial automatic stack variables: uninitialized (default)"
+ Flags<[CC1Option, CoreOption]>, HelpText<"Initialize trivial automatic stack variables: uninitialized (default)"
" | pattern">, Values<"uninitialized,pattern">;
-def enable_trivial_var_init_zero : Joined<["-"], "enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang">,
- Flags<[CC1Option]>,
+def enable_trivial_var_init_zero : Flag<["-"], "enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang">,
+ Flags<[CC1Option, CoreOption]>,
HelpText<"Trivial automatic variable initialization to zero is only here for benchmarks, it'll eventually be removed, and I'm OK with that because I'm only using it to benchmark">;
def fstandalone_debug : Flag<["-"], "fstandalone-debug">, Group<f_Group>, Flags<[CoreOption]>,
HelpText<"Emit full debug info for all types used by the program">;
@@ -1757,7 +1816,16 @@ def Wframe_larger_than_EQ : Joined<["-"], "Wframe-larger-than=">, Group<f_Group>
def : Flag<["-"], "fterminated-vtables">, Alias<fapple_kext>;
def fthreadsafe_statics : Flag<["-"], "fthreadsafe-statics">, Group<f_Group>;
def ftime_report : Flag<["-"], "ftime-report">, Group<f_Group>, Flags<[CC1Option]>;
-def ftime_trace : Flag<["-"], "ftime-trace">, Group<f_Group>, Flags<[CC1Option, CoreOption]>;
+def ftime_trace : Flag<["-"], "ftime-trace">, Group<f_Group>,
+ HelpText<"Turn on time profiler. Generates JSON file based on output filename.">,
+ DocBrief<[{
+Turn on time profiler. Generates JSON file based on output filename. Results
+can be analyzed with chrome://tracing or `Speedscope App
+<https://www.speedscope.app>`_ for flamegraph visualization.}]>,
+ Flags<[CC1Option, CoreOption]>;
+def ftime_trace_granularity_EQ : Joined<["-"], "ftime-trace-granularity=">, Group<f_Group>,
+ HelpText<"Minimum time granularity (in microseconds) traced by time profiler">,
+ Flags<[CC1Option, CoreOption]>;
def ftlsmodel_EQ : Joined<["-"], "ftls-model=">, Group<f_Group>, Flags<[CC1Option]>;
def ftrapv : Flag<["-"], "ftrapv">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Trap on integer overflow">;
@@ -1791,6 +1859,7 @@ def fuse_init_array : Flag<["-"], "fuse-init-array">, Group<f_Group>, Flags<[CC1
HelpText<"Use .init_array instead of .ctors">;
def fno_var_tracking : Flag<["-"], "fno-var-tracking">, Group<clang_ignored_f_Group>;
def fverbose_asm : Flag<["-"], "fverbose-asm">, Group<f_Group>;
+def dA : Flag<["-"], "dA">, Alias<fverbose_asm>;
def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group<f_Group>,
HelpText<"Set the default symbol visibility for all global declarations">, Values<"hidden,default">;
def fvisibility_inlines_hidden : Flag<["-"], "fvisibility-inlines-hidden">, Group<f_Group>,
@@ -1816,6 +1885,13 @@ def fforce_emit_vtables : Flag<["-"], "fforce-emit-vtables">, Group<f_Group>,
HelpText<"Emits more virtual tables to improve devirtualization">;
def fno_force_emit_vtables : Flag<["-"], "fno-force-emit-vtables">, Group<f_Group>,
Flags<[CoreOption]>;
+
+def fvirtual_function_elimination : Flag<["-"], "fvirtual-function-elimination">, Group<f_Group>,
+ Flags<[CoreOption, CC1Option]>,
+ HelpText<"Enables dead virtual function elimination optimization. Requires -flto=full">;
+def fno_virtual_function_elimination : Flag<["-"], "fno-virtual-function_elimination">, Group<f_Group>,
+ Flags<[CoreOption]>;
+
def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Treat signed integer overflow as two's complement">;
def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>, Flags<[CC1Option]>,
@@ -2023,9 +2099,14 @@ def malign_jumps_EQ : Joined<["-"], "malign-jumps=">, Group<clang_ignored_m_Grou
def mfancy_math_387 : Flag<["-"], "mfancy-math-387">, Group<clang_ignored_m_Group>;
def mlong_calls : Flag<["-"], "mlong-calls">, Group<m_Group>,
HelpText<"Generate branches with extended addressability, usually via indirect jumps.">;
-def mlong_double_64 : Flag<["-"], "mlong-double-64">, Group<f_Group>, Flags<[CC1Option]>,
+def LongDouble_Group : OptionGroup<"<LongDouble group>">, Group<m_Group>,
+ DocName<"Long double flags">,
+ DocBrief<[{Selects the long double implementation}]>;
+def mlong_double_64 : Flag<["-"], "mlong-double-64">, Group<LongDouble_Group>, Flags<[CC1Option]>,
HelpText<"Force long double to be 64 bits">;
-def mlong_double_128 : Flag<["-"], "mlong-double-128">, Group<f_Group>, Flags<[CC1Option]>,
+def mlong_double_80 : Flag<["-"], "mlong-double-80">, Group<LongDouble_Group>, Flags<[CC1Option]>,
+ HelpText<"Force long double to be 80 bits, padded to 128 bits for storage">;
+def mlong_double_128 : Flag<["-"], "mlong-double-128">, Group<LongDouble_Group>, Flags<[CC1Option]>,
HelpText<"Force long double to be 128 bits">;
def mno_long_calls : Flag<["-"], "mno-long-calls">, Group<m_Group>,
HelpText<"Restore the default behaviour of not generating long calls">;
@@ -2138,6 +2219,12 @@ def msave_restore : Flag<["-"], "msave-restore">, Group<m_riscv_Features_Group>,
HelpText<"Enable using library calls for save and restore">;
def mno_save_restore : Flag<["-"], "mno-save-restore">, Group<m_riscv_Features_Group>,
HelpText<"Disable using library calls for save and restore">;
+def mcmodel_EQ_medlow : Flag<["-"], "mcmodel=medlow">, Group<m_riscv_Features_Group>,
+ Flags<[CC1Option]>, Alias<mcmodel_EQ>, AliasArgs<["small"]>,
+ HelpText<"Equivalent to -mcmodel=small, compatible with RISC-V gcc.">;
+def mcmodel_EQ_medany : Flag<["-"], "mcmodel=medany">, Group<m_riscv_Features_Group>,
+ Flags<[CC1Option]>, Alias<mcmodel_EQ>, AliasArgs<["medium"]>,
+ HelpText<"Equivalent to -mcmodel=medium, compatible with RISC-V gcc.">;
def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_arm_Features_Group>,
HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64 only)">;
@@ -2241,6 +2328,8 @@ def faltivec : Flag<["-"], "faltivec">, Group<f_Group>, Flags<[DriverOption]>;
def fno_altivec : Flag<["-"], "fno-altivec">, Group<f_Group>, Flags<[DriverOption]>;
def maltivec : Flag<["-"], "maltivec">, Group<m_ppc_Features_Group>;
def mno_altivec : Flag<["-"], "mno-altivec">, Group<m_ppc_Features_Group>;
+def mspe : Flag<["-"], "mspe">, Group<m_ppc_Features_Group>;
+def mno_spe : Flag<["-"], "mno-spe">, Group<m_ppc_Features_Group>;
def mvsx : Flag<["-"], "mvsx">, Group<m_ppc_Features_Group>;
def mno_vsx : Flag<["-"], "mno-vsx">, Group<m_ppc_Features_Group>;
def msecure_plt : Flag<["-"], "msecure-plt">, Group<m_ppc_Features_Group>;
@@ -2309,7 +2398,7 @@ def mno_backchain : Flag<["-"], "mno-backchain">, Group<m_Group>, Flags<[DriverO
def mno_warn_nonportable_cfstrings : Flag<["-"], "mno-warn-nonportable-cfstrings">, Group<m_Group>;
def mno_omit_leaf_frame_pointer : Flag<["-"], "mno-omit-leaf-frame-pointer">, Group<m_Group>;
def momit_leaf_frame_pointer : Flag<["-"], "momit-leaf-frame-pointer">, Group<m_Group>,
- HelpText<"Omit frame pointer setup for leaf functions">, Flags<[CC1Option]>;
+ HelpText<"Omit frame pointer setup for leaf functions">;
def moslib_EQ : Joined<["-"], "moslib=">, Group<m_Group>;
def mpascal_strings : Flag<["-"], "mpascal-strings">, Alias<fpascal_strings>;
def mred_zone : Flag<["-"], "mred-zone">, Group<m_Group>;
@@ -2340,7 +2429,7 @@ def mpie_copy_relocations : Flag<["-"], "mpie-copy-relocations">, Group<m_Group>
Flags<[CC1Option]>,
HelpText<"Use copy relocations support for PIE builds">;
def mno_pie_copy_relocations : Flag<["-"], "mno-pie-copy-relocations">, Group<m_Group>;
-def mfentry : Flag<["-"], "mfentry">, HelpText<"Insert calls to fentry at function entry (x86 only)">,
+def mfentry : Flag<["-"], "mfentry">, HelpText<"Insert calls to fentry at function entry (x86/SystemZ only)">,
Flags<[CC1Option]>, Group<m_Group>;
def mips16 : Flag<["-"], "mips16">, Group<m_mips_Features_Group>;
def mno_mips16 : Flag<["-"], "mno-mips16">, Group<m_mips_Features_Group>;
@@ -2506,7 +2595,9 @@ def no__dead__strip__inits__and__terms : Flag<["-"], "no_dead_strip_inits_and_te
def nobuiltininc : Flag<["-"], "nobuiltininc">, Flags<[CC1Option, CoreOption]>,
HelpText<"Disable builtin #include directories">;
def nocudainc : Flag<["-"], "nocudainc">;
-def nocudalib : Flag<["-"], "nocudalib">;
+def nogpulib : Flag<["-"], "nogpulib">,
+ HelpText<"Do not link device library for CUDA/HIP device compilation">;
+def : Flag<["-"], "nocudalib">, Alias<nogpulib>;
def nodefaultlibs : Flag<["-"], "nodefaultlibs">;
def nofixprebinding : Flag<["-"], "nofixprebinding">;
def nolibc : Flag<["-"], "nolibc">;
@@ -2627,11 +2718,15 @@ def std_EQ : Joined<["-", "--"], "std=">, Flags<[CC1Option]>,
const char *Values =
#define LANGSTANDARD(id, name, lang, desc, features) name ","
#define LANGSTANDARD_ALIAS(id, alias) alias ","
- #include "clang/Frontend/LangStandards.def"
+ #include "clang/Basic/LangStandards.def"
;
}]>;
def stdlib_EQ : Joined<["-", "--"], "stdlib=">, Flags<[CC1Option]>,
HelpText<"C++ standard library to use">, Values<"libc++,libstdc++,platform">;
+def stdlibxx_isystem : JoinedOrSeparate<["-"], "stdlib++-isystem">,
+ Group<clang_i_Group>,
+ HelpText<"Use directory as the C++ standard library include path">,
+ Flags<[DriverOption]>, MetaVarName<"<directory>">;
def unwindlib_EQ : Joined<["-", "--"], "unwindlib=">, Flags<[CC1Option]>,
HelpText<"Unwind library to use">, Values<"libgcc,unwindlib,platform">;
def sub__library : JoinedOrSeparate<["-"], "sub_library">;
@@ -2711,7 +2806,6 @@ def _mhwdiv : Separate<["--"], "mhwdiv">, Alias<mhwdiv_EQ>;
def _CLASSPATH_EQ : Joined<["--"], "CLASSPATH=">, Alias<fclasspath_EQ>;
def _CLASSPATH : Separate<["--"], "CLASSPATH">, Alias<fclasspath_EQ>;
def _all_warnings : Flag<["--"], "all-warnings">, Alias<Wall>;
-def _analyze_auto : Flag<["--"], "analyze-auto">, Flags<[DriverOption]>;
def _analyzer_no_default_checks : Flag<["--"], "analyzer-no-default-checks">, Flags<[DriverOption]>;
def _analyzer_output : JoinedOrSeparate<["--"], "analyzer-output">, Flags<[DriverOption]>,
HelpText<"Static analyzer report output format (html|plist|plist-multi-file|plist-html|text).">;
@@ -2972,8 +3066,6 @@ def mmovdiri : Flag<["-"], "mmovdiri">, Group<m_x86_Features_Group>;
def mno_movdiri : Flag<["-"], "mno-movdiri">, Group<m_x86_Features_Group>;
def mmovdir64b : Flag<["-"], "mmovdir64b">, Group<m_x86_Features_Group>;
def mno_movdir64b : Flag<["-"], "mno-movdir64b">, Group<m_x86_Features_Group>;
-def mmpx : Flag<["-"], "mmpx">, Group<m_x86_Features_Group>;
-def mno_mpx : Flag<["-"], "mno-mpx">, Group<m_x86_Features_Group>;
def mmwaitx : Flag<["-"], "mmwaitx">, Group<m_x86_Features_Group>;
def mno_mwaitx : Flag<["-"], "mno-mwaitx">, Group<m_x86_Features_Group>;
def mpku : Flag<["-"], "mpku">, Group<m_x86_Features_Group>;
diff --git a/include/clang/Driver/Phases.h b/include/clang/Driver/Phases.h
index 7199c657848c..63931c00c890 100644
--- a/include/clang/Driver/Phases.h
+++ b/include/clang/Driver/Phases.h
@@ -20,7 +20,8 @@ namespace phases {
Compile,
Backend,
Assemble,
- Link
+ Link,
+ IfsMerge,
};
enum {
diff --git a/include/clang/Driver/SanitizerArgs.h b/include/clang/Driver/SanitizerArgs.h
index 957e752b6877..c37499e0f201 100644
--- a/include/clang/Driver/SanitizerArgs.h
+++ b/include/clang/Driver/SanitizerArgs.h
@@ -32,6 +32,7 @@ class SanitizerArgs {
bool MsanUseAfterDtor = true;
bool CfiCrossDso = false;
bool CfiICallGeneralizePointers = false;
+ bool CfiCanonicalJumpTables = false;
int AsanFieldPadding = 0;
bool SharedRuntime = false;
bool AsanUseAfterScope = true;
@@ -41,6 +42,7 @@ class SanitizerArgs {
bool AsanInvalidPointerCmp = false;
bool AsanInvalidPointerSub = false;
std::string HwasanAbi;
+ bool LinkRuntimes = true;
bool LinkCXXRuntimes = false;
bool NeedPIE = false;
bool SafeStackRuntime = false;
@@ -59,7 +61,9 @@ class SanitizerArgs {
bool needsSharedRt() const { return SharedRuntime; }
bool needsAsanRt() const { return Sanitizers.has(SanitizerKind::Address); }
- bool needsHwasanRt() const { return Sanitizers.has(SanitizerKind::HWAddress); }
+ bool needsHwasanRt() const {
+ return Sanitizers.has(SanitizerKind::HWAddress);
+ }
bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); }
bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); }
bool needsFuzzer() const { return Sanitizers.has(SanitizerKind::Fuzzer); }
@@ -80,6 +84,7 @@ class SanitizerArgs {
bool requiresPIE() const;
bool needsUnwindTables() const;
bool needsLTO() const;
+ bool linkRuntimes() const { return LinkRuntimes; }
bool linkCXXRuntimes() const { return LinkCXXRuntimes; }
bool hasCrossDsoCfi() const { return CfiCrossDso; }
bool hasAnySanitizer() const { return !Sanitizers.empty(); }
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index 7dd3db376c8c..f0676eee2d6c 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -136,13 +136,17 @@ private:
mutable std::unique_ptr<Tool> Clang;
mutable std::unique_ptr<Tool> Assemble;
mutable std::unique_ptr<Tool> Link;
+ mutable std::unique_ptr<Tool> IfsMerge;
mutable std::unique_ptr<Tool> OffloadBundler;
+ mutable std::unique_ptr<Tool> OffloadWrapper;
Tool *getClang() const;
Tool *getAssemble() const;
Tool *getLink() const;
+ Tool *getIfsMerge() const;
Tool *getClangAs() const;
Tool *getOffloadBundler() const;
+ Tool *getOffloadWrapper() const;
mutable std::unique_ptr<SanitizerArgs> SanitizerArguments;
mutable std::unique_ptr<XRayArgs> XRayArguments;
@@ -542,6 +546,11 @@ public:
AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const;
+ /// AddClangCXXStdlibIsystemArgs - Add the clang -cc1 level arguments to set
+ /// the specified include paths for the C++ standard library.
+ void AddClangCXXStdlibIsystemArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+
/// Returns if the C++ standard library should be linked in.
/// Note that e.g. -lm should still be linked even if this returns false.
bool ShouldLinkCXXStdlib(const llvm::opt::ArgList &Args) const;
diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def
index b45789d4b314..79e8d109cd97 100644
--- a/include/clang/Driver/Types.def
+++ b/include/clang/Driver/Types.def
@@ -29,77 +29,74 @@
// The fourth value is the suffix to use when creating temporary files
// of this type, or null if unspecified.
-// The fifth value is a string containing option flags. Valid values:
-// a - The type should only be assembled.
-// p - The type should only be precompiled.
-// u - The type can be user specified (with -x).
-// m - Precompiling this type produces a module file.
-// A - The type's temporary suffix should be appended when generating
-// outputs of this type.
-
+// The final value is a variadic list of phases for each type. Eventually the
+// options flag string will be replaced with this variadic list.
+// Most of the options in Flags have been removed in favor of subsuming their
+// meaning from the phases list.
// C family source language (with and without preprocessing).
-TYPE("cpp-output", PP_C, INVALID, "i", "u")
-TYPE("c", C, PP_C, "c", "u")
-TYPE("cl", CL, PP_C, "cl", "u")
-TYPE("cuda-cpp-output", PP_CUDA, INVALID, "cui", "u")
-TYPE("cuda", CUDA, PP_CUDA, "cu", "u")
-TYPE("cuda", CUDA_DEVICE, PP_CUDA, "cu", "")
-TYPE("hip-cpp-output", PP_HIP, INVALID, "cui", "u")
-TYPE("hip", HIP, PP_HIP, "cu", "u")
-TYPE("hip", HIP_DEVICE, PP_HIP, "cu", "")
-TYPE("objective-c-cpp-output", PP_ObjC, INVALID, "mi", "u")
-TYPE("objc-cpp-output", PP_ObjC_Alias, INVALID, "mi", "u")
-TYPE("objective-c", ObjC, PP_ObjC, "m", "u")
-TYPE("c++-cpp-output", PP_CXX, INVALID, "ii", "u")
-TYPE("c++", CXX, PP_CXX, "cpp", "u")
-TYPE("objective-c++-cpp-output", PP_ObjCXX, INVALID, "mii", "u")
-TYPE("objc++-cpp-output", PP_ObjCXX_Alias, INVALID, "mii", "u")
-TYPE("objective-c++", ObjCXX, PP_ObjCXX, "mm", "u")
-TYPE("renderscript", RenderScript, PP_C, "rs", "u")
+TYPE("cpp-output", PP_C, INVALID, "i", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("c", C, PP_C, "c", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("cl", CL, PP_C, "cl", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("cuda-cpp-output", PP_CUDA, INVALID, "cui", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("cuda", CUDA, PP_CUDA, "cu", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("cuda", CUDA_DEVICE, PP_CUDA, "cu", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("hip-cpp-output", PP_HIP, INVALID, "cui", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("hip", HIP, PP_HIP, "cu", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("hip", HIP_DEVICE, PP_HIP, "cu", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("objective-c-cpp-output", PP_ObjC, INVALID, "mi", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("objc-cpp-output", PP_ObjC_Alias, INVALID, "mi", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("objective-c", ObjC, PP_ObjC, "m", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("c++-cpp-output", PP_CXX, INVALID, "ii", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("c++", CXX, PP_CXX, "cpp", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("objective-c++-cpp-output", PP_ObjCXX, INVALID, "mii", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("objc++-cpp-output", PP_ObjCXX_Alias, INVALID, "mii", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("objective-c++", ObjCXX, PP_ObjCXX, "mm", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("renderscript", RenderScript, PP_C, "rs", phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
// C family input files to precompile.
-TYPE("c-header-cpp-output", PP_CHeader, INVALID, "i", "p")
-TYPE("c-header", CHeader, PP_CHeader, "h", "pu")
-TYPE("cl-header", CLHeader, PP_CHeader, "h", "pu")
-TYPE("objective-c-header-cpp-output", PP_ObjCHeader, INVALID, "mi", "p")
-TYPE("objective-c-header", ObjCHeader, PP_ObjCHeader, "h", "pu")
-TYPE("c++-header-cpp-output", PP_CXXHeader, INVALID, "ii", "p")
-TYPE("c++-header", CXXHeader, PP_CXXHeader, "hh", "pu")
-TYPE("objective-c++-header-cpp-output", PP_ObjCXXHeader, INVALID, "mii", "p")
-TYPE("objective-c++-header", ObjCXXHeader, PP_ObjCXXHeader, "h", "pu")
-TYPE("c++-module", CXXModule, PP_CXXModule, "cppm", "mu")
-TYPE("c++-module-cpp-output", PP_CXXModule, INVALID, "iim", "m")
+TYPE("c-header-cpp-output", PP_CHeader, INVALID, "i", phases::Precompile)
+TYPE("c-header", CHeader, PP_CHeader, "h", phases::Preprocess, phases::Precompile)
+TYPE("cl-header", CLHeader, PP_CHeader, "h", phases::Preprocess, phases::Precompile)
+TYPE("objective-c-header-cpp-output", PP_ObjCHeader, INVALID, "mi", phases::Precompile)
+TYPE("objective-c-header", ObjCHeader, PP_ObjCHeader, "h", phases::Preprocess, phases::Precompile)
+TYPE("c++-header-cpp-output", PP_CXXHeader, INVALID, "ii", phases::Precompile)
+TYPE("c++-header", CXXHeader, PP_CXXHeader, "hh", phases::Preprocess, phases::Precompile)
+TYPE("objective-c++-header-cpp-output", PP_ObjCXXHeader, INVALID, "mii", phases::Precompile)
+TYPE("objective-c++-header", ObjCXXHeader, PP_ObjCXXHeader, "h", phases::Preprocess, phases::Precompile)
+TYPE("c++-module", CXXModule, PP_CXXModule, "cppm", phases::Preprocess, phases::Precompile, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("c++-module-cpp-output", PP_CXXModule, INVALID, "iim", phases::Precompile, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
// Other languages.
-TYPE("ada", Ada, INVALID, nullptr, "u")
-TYPE("assembler", PP_Asm, INVALID, "s", "au")
-TYPE("assembler-with-cpp", Asm, PP_Asm, "S", "au")
-TYPE("f95", PP_Fortran, INVALID, nullptr, "u")
-TYPE("f95-cpp-input", Fortran, PP_Fortran, nullptr, "u")
-TYPE("java", Java, INVALID, nullptr, "u")
+TYPE("ada", Ada, INVALID, nullptr, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("assembler", PP_Asm, INVALID, "s", phases::Assemble, phases::Link)
+TYPE("assembler-with-cpp", Asm, PP_Asm, "S", phases::Preprocess, phases::Assemble, phases::Link)
+TYPE("f95", PP_Fortran, INVALID, nullptr, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("f95-cpp-input", Fortran, PP_Fortran, nullptr, phases::Preprocess, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("java", Java, INVALID, nullptr, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
// LLVM IR/LTO types. We define separate types for IR and LTO because LTO
// outputs should use the standard suffixes.
-TYPE("ir", LLVM_IR, INVALID, "ll", "u")
-TYPE("ir", LLVM_BC, INVALID, "bc", "u")
-TYPE("lto-ir", LTO_IR, INVALID, "s", "")
-TYPE("lto-bc", LTO_BC, INVALID, "o", "")
+TYPE("ir", LLVM_IR, INVALID, "ll", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("ir", LLVM_BC, INVALID, "bc", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("lto-ir", LTO_IR, INVALID, "s", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("lto-bc", LTO_BC, INVALID, "o", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
// Misc.
-TYPE("ast", AST, INVALID, "ast", "u")
-TYPE("ifs", IFS, INVALID, "ifs", "u")
-TYPE("pcm", ModuleFile, INVALID, "pcm", "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, nullptr, "u")
-TYPE("image", Image, INVALID, "out", "")
-TYPE("dSYM", dSYM, INVALID, "dSYM", "A")
-TYPE("dependencies", Dependencies, INVALID, "d", "")
-TYPE("cuda-fatbin", CUDA_FATBIN, INVALID, "fatbin","A")
-TYPE("hip-fatbin", HIP_FATBIN, INVALID, "hipfb", "A")
-TYPE("none", Nothing, INVALID, nullptr, "u")
+TYPE("ast", AST, INVALID, "ast", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("ifs", IFS, INVALID, "ifs", phases::IfsMerge)
+TYPE("ifs-cpp", IFS_CPP, INVALID, "ifs", phases::Compile, phases::IfsMerge)
+TYPE("pcm", ModuleFile, INVALID, "pcm", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("plist", Plist, INVALID, "plist", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("rewritten-objc", RewrittenObjC,INVALID, "cpp", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("rewritten-legacy-objc", RewrittenLegacyObjC,INVALID, "cpp", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("remap", Remap, INVALID, "remap", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("precompiled-header", PCH, INVALID, "gch", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("object", Object, INVALID, "o", phases::Link)
+TYPE("treelang", Treelang, INVALID, nullptr, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("image", Image, INVALID, "out", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("dSYM", dSYM, INVALID, "dSYM", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("dependencies", Dependencies, INVALID, "d", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("cuda-fatbin", CUDA_FATBIN, INVALID, "fatbin", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("hip-fatbin", HIP_FATBIN, INVALID, "hipfb", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
+TYPE("none", Nothing, INVALID, nullptr, phases::Compile, phases::Backend, phases::Assemble, phases::Link)
diff --git a/include/clang/Driver/Types.h b/include/clang/Driver/Types.h
index 53afada7abca..a605450e6e3d 100644
--- a/include/clang/Driver/Types.h
+++ b/include/clang/Driver/Types.h
@@ -11,16 +11,18 @@
#include "clang/Driver/Phases.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Option/ArgList.h"
namespace llvm {
class StringRef;
}
namespace clang {
namespace driver {
+class Driver;
namespace types {
enum ID {
TY_INVALID,
-#define TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, FLAGS) TY_##ID,
+#define TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, ...) TY_##ID,
#include "clang/Driver/Types.def"
#undef TYPE
TY_LAST
@@ -100,6 +102,9 @@ namespace types {
void getCompilationPhases(
ID Id,
llvm::SmallVectorImpl<phases::ID> &Phases);
+ void getCompilationPhases(const clang::driver::Driver &Driver,
+ llvm::opt::DerivedArgList &DAL, ID Id,
+ llvm::SmallVectorImpl<phases::ID> &Phases);
/// lookupCXXTypeForCType - Lookup CXX input type that corresponds to given
/// C type (used for clang++ emulation of g++ behaviour)
diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h
index 6388e4fc1727..7e71b7e8b167 100644
--- a/include/clang/Format/Format.h
+++ b/include/clang/Format/Format.h
@@ -216,10 +216,37 @@ struct FormatStyle {
/// \endcode
bool AllowAllParametersOfDeclarationOnNextLine;
- /// Allows contracting simple braced statements to a single line.
- ///
- /// E.g., this allows ``if (a) { return; }`` to be put on a single line.
- bool AllowShortBlocksOnASingleLine;
+ /// Different styles for merging short blocks containing at most one
+ /// statement.
+ enum ShortBlockStyle {
+ /// Never merge blocks into a single line.
+ /// \code
+ /// while (true) {
+ /// }
+ /// while (true) {
+ /// continue;
+ /// }
+ /// \endcode
+ SBS_Never,
+ /// Only merge empty blocks.
+ /// \code
+ /// while (true) {}
+ /// while (true) {
+ /// continue;
+ /// }
+ /// \endcode
+ SBS_Empty,
+ /// Always merge short blocks into a single line.
+ /// \code
+ /// while (true) {}
+ /// while (true) { continue; }
+ /// \endcode
+ SBS_Always,
+ };
+
+ /// Dependent on the value, ``while (true) { continue; }`` can be put on a
+ /// single line.
+ ShortBlockStyle AllowShortBlocksOnASingleLine;
/// If ``true``, short case labels will be contracted to a single line.
/// \code
@@ -462,38 +489,38 @@ struct FormatStyle {
/// Different ways to break after the template declaration.
enum BreakTemplateDeclarationsStyle {
- /// Do not force break before declaration.
- /// ``PenaltyBreakTemplateDeclaration`` is taken into account.
- /// \code
- /// template <typename T> T foo() {
- /// }
- /// template <typename T> T foo(int aaaaaaaaaaaaaaaaaaaaa,
- /// int bbbbbbbbbbbbbbbbbbbbb) {
- /// }
- /// \endcode
- BTDS_No,
- /// Force break after template declaration only when the following
- /// declaration spans multiple lines.
- /// \code
- /// template <typename T> T foo() {
- /// }
- /// template <typename T>
- /// T foo(int aaaaaaaaaaaaaaaaaaaaa,
- /// int bbbbbbbbbbbbbbbbbbbbb) {
- /// }
- /// \endcode
- BTDS_MultiLine,
- /// Always break after template declaration.
- /// \code
- /// template <typename T>
- /// T foo() {
- /// }
- /// template <typename T>
- /// T foo(int aaaaaaaaaaaaaaaaaaaaa,
- /// int bbbbbbbbbbbbbbbbbbbbb) {
- /// }
- /// \endcode
- BTDS_Yes
+ /// Do not force break before declaration.
+ /// ``PenaltyBreakTemplateDeclaration`` is taken into account.
+ /// \code
+ /// template <typename T> T foo() {
+ /// }
+ /// template <typename T> T foo(int aaaaaaaaaaaaaaaaaaaaa,
+ /// int bbbbbbbbbbbbbbbbbbbbb) {
+ /// }
+ /// \endcode
+ BTDS_No,
+ /// Force break after template declaration only when the following
+ /// declaration spans multiple lines.
+ /// \code
+ /// template <typename T> T foo() {
+ /// }
+ /// template <typename T>
+ /// T foo(int aaaaaaaaaaaaaaaaaaaaa,
+ /// int bbbbbbbbbbbbbbbbbbbbb) {
+ /// }
+ /// \endcode
+ BTDS_MultiLine,
+ /// Always break after template declaration.
+ /// \code
+ /// template <typename T>
+ /// T foo() {
+ /// }
+ /// template <typename T>
+ /// T foo(int aaaaaaaaaaaaaaaaaaaaa,
+ /// int bbbbbbbbbbbbbbbbbbbbb) {
+ /// }
+ /// \endcode
+ BTDS_Yes
};
/// The template declaration breaking style to use.
@@ -706,6 +733,32 @@ struct FormatStyle {
/// B
/// };
/// \endcode
+ BS_Whitesmiths,
+ /// Like ``Allman`` but always indent braces and line up code with braces.
+ /// \code
+ /// try
+ /// {
+ /// foo();
+ /// }
+ /// catch ()
+ /// {
+ /// }
+ /// void foo() { bar(); }
+ /// class foo
+ /// {
+ /// };
+ /// if (foo())
+ /// {
+ /// }
+ /// else
+ /// {
+ /// }
+ /// enum X : int
+ /// {
+ /// A,
+ /// B
+ /// };
+ /// \endcode
BS_GNU,
/// Like ``Attach``, but break before functions.
/// \code
@@ -729,6 +782,40 @@ struct FormatStyle {
/// The brace breaking style to use.
BraceBreakingStyle BreakBeforeBraces;
+ // Different ways to wrap braces after control statements.
+ enum BraceWrappingAfterControlStatementStyle {
+ /// Never wrap braces after a control statement.
+ /// \code
+ /// if (foo()) {
+ /// } else {
+ /// }
+ /// for (int i = 0; i < 10; ++i) {
+ /// }
+ /// \endcode
+ BWACS_Never,
+ /// Only wrap braces after a multi-line control statement.
+ /// \code
+ /// if (foo && bar &&
+ /// baz)
+ /// {
+ /// quux();
+ /// }
+ /// while (foo || bar) {
+ /// }
+ /// \endcode
+ BWACS_MultiLine,
+ /// Always wrap braces after a control statement.
+ /// \code
+ /// if (foo())
+ /// {
+ /// } else
+ /// {}
+ /// for (int i = 0; i < 10; ++i)
+ /// {}
+ /// \endcode
+ BWACS_Always
+ };
+
/// Precise control over the wrapping of braces.
/// \code
/// # Should be declared this way:
@@ -764,23 +851,7 @@ struct FormatStyle {
/// \endcode
bool AfterClass;
/// Wrap control statements (``if``/``for``/``while``/``switch``/..).
- /// \code
- /// true:
- /// if (foo())
- /// {
- /// } else
- /// {}
- /// for (int i = 0; i < 10; ++i)
- /// {}
- ///
- /// false:
- /// if (foo()) {
- /// } else {
- /// }
- /// for (int i = 0; i < 10; ++i) {
- /// }
- /// \endcode
- bool AfterControlStatement;
+ BraceWrappingAfterControlStatementStyle AfterControlStatement;
/// Wrap enum definitions.
/// \code
/// true:
@@ -1238,6 +1309,22 @@ struct FormatStyle {
/// \endcode
bool IndentCaseLabels;
+ /// Indent goto labels.
+ ///
+ /// When ``false``, goto labels are flushed left.
+ /// \code
+ /// true: false:
+ /// int f() { vs. int f() {
+ /// if (foo()) { if (foo()) {
+ /// label1: label1:
+ /// bar(); bar();
+ /// } }
+ /// label2: label2:
+ /// return 1; return 1;
+ /// } }
+ /// \endcode
+ bool IndentGotoLabels;
+
/// Options for indenting preprocessor directives.
enum PPDirectiveIndentStyle {
/// Does not indent any directives.
@@ -1711,8 +1798,8 @@ struct FormatStyle {
/// If ``false``, spaces will be removed before assignment operators.
/// \code
/// true: false:
- /// int a = 5; vs. int a=5;
- /// a += 42 a+=42;
+ /// int a = 5; vs. int a= 5;
+ /// a += 42; a+= 42;
/// \endcode
bool SpaceBeforeAssignmentOperators;
@@ -1799,6 +1886,14 @@ struct FormatStyle {
/// \endcode
bool SpaceBeforeRangeBasedForLoopColon;
+ /// If ``true``, spaces will be inserted into ``{}``.
+ /// \code
+ /// true: false:
+ /// void f() { } vs. void f() {}
+ /// while (true) { } while (true) {}
+ /// \endcode
+ bool SpaceInEmptyBlock;
+
/// If ``true``, spaces may be inserted into ``()``.
/// \code
/// true: false:
@@ -1868,15 +1963,32 @@ struct FormatStyle {
/// \endcode
bool SpacesInSquareBrackets;
- /// Supported language standards.
+ /// Supported language standards for parsing and formatting C++ constructs.
+ /// \code
+ /// Latest: vector<set<int>>
+ /// c++03 vs. vector<set<int> >
+ /// \endcode
+ ///
+ /// The correct way to spell a specific language version is e.g. ``c++11``.
+ /// The historical aliases ``Cpp03`` and ``Cpp11`` are deprecated.
enum LanguageStandard {
- /// Use C++03-compatible syntax.
+ /// c++03: Parse and format as C++03.
LS_Cpp03,
- /// Use features of C++11, C++14 and C++1z (e.g. ``A<A<int>>`` instead of
- /// ``A<A<int> >``).
+ /// c++11: Parse and format as C++11.
LS_Cpp11,
- /// Automatic detection based on the input.
- LS_Auto
+ /// c++14: Parse and format as C++14.
+ LS_Cpp14,
+ /// c++17: Parse and format as C++17.
+ LS_Cpp17,
+ /// c++20: Parse and format as C++20.
+ LS_Cpp20,
+ /// Latest: Parse and format using the latest supported language version.
+ /// 'Cpp11' is an alias for LS_Latest for historical reasons.
+ LS_Latest,
+
+ /// Auto: Automatic detection based on the input.
+ /// Parse using the latest language version. Format based on detected input.
+ LS_Auto,
};
/// Format compatible with this standard, e.g. use ``A<A<int> >``
@@ -1955,6 +2067,7 @@ struct FormatStyle {
IncludeStyle.IncludeBlocks == R.IncludeStyle.IncludeBlocks &&
IncludeStyle.IncludeCategories == R.IncludeStyle.IncludeCategories &&
IndentCaseLabels == R.IndentCaseLabels &&
+ IndentGotoLabels == R.IndentGotoLabels &&
IndentPPDirectives == R.IndentPPDirectives &&
IndentWidth == R.IndentWidth && Language == R.Language &&
IndentWrappedFunctionNames == R.IndentWrappedFunctionNames &&
@@ -1995,6 +2108,7 @@ struct FormatStyle {
SpaceBeforeParens == R.SpaceBeforeParens &&
SpaceBeforeRangeBasedForLoopColon ==
R.SpaceBeforeRangeBasedForLoopColon &&
+ SpaceInEmptyBlock == R.SpaceInEmptyBlock &&
SpaceInEmptyParentheses == R.SpaceInEmptyParentheses &&
SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments &&
SpacesInAngles == R.SpacesInAngles &&
@@ -2072,6 +2186,10 @@ FormatStyle getWebKitStyle();
/// http://www.gnu.org/prep/standards/standards.html
FormatStyle getGNUStyle();
+/// Returns a format style complying with Microsoft style guide:
+/// https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference?view=vs-2017
+FormatStyle getMicrosoftStyle(FormatStyle::LanguageKind Language);
+
/// Returns style indicating formatting should be not applied at all.
FormatStyle getNoStyle();
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 7fb1d2d93380..a36655150d4e 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -315,7 +315,7 @@ public:
CodeCompletionTUInfo &getCodeCompletionTUInfo() {
if (!CCTUInfo)
- CCTUInfo = llvm::make_unique<CodeCompletionTUInfo>(
+ CCTUInfo = std::make_unique<CodeCompletionTUInfo>(
std::make_shared<GlobalCodeCompletionAllocator>());
return *CCTUInfo;
}
@@ -390,7 +390,7 @@ private:
/// just about any usage.
/// Becomes a noop in release mode; only useful for debug mode checking.
class ConcurrencyState {
- void *Mutex; // a llvm::sys::MutexImpl in debug;
+ void *Mutex; // a std::recursive_mutex in debug;
public:
ConcurrencyState();
@@ -832,6 +832,7 @@ public:
SkipFunctionBodiesScope::None,
bool SingleFileParse = false, bool UserFilesAreVolatile = false,
bool ForSerialization = false,
+ bool RetainExcludedConditionalBlocks = false,
llvm::Optional<StringRef> ModuleFormat = llvm::None,
std::unique_ptr<ASTUnit> *ErrAST = nullptr,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = nullptr);
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index eb49c53ff40b..d15bdc4665a3 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -155,6 +155,12 @@ class CompilerInstance : public ModuleLoader {
/// One or more modules failed to build.
bool ModuleBuildFailed = false;
+ /// The stream for verbose output if owned, otherwise nullptr.
+ std::unique_ptr<raw_ostream> OwnedVerboseOutputStream;
+
+ /// The stream for verbose output.
+ raw_ostream *VerboseOutputStream = &llvm::errs();
+
/// Holds information about the output file.
///
/// If TempFilename is not empty we must rename it to Filename at the end.
@@ -217,9 +223,6 @@ public:
/// \param Act - The action to execute.
/// \return - True on success.
//
- // FIXME: This function should take the stream to write any debugging /
- // verbose output to as an argument.
- //
// FIXME: Eliminate the llvm_shutdown requirement, that should either be part
// of the context or else not CompilerInstance specific.
bool ExecuteAction(FrontendAction &Act);
@@ -350,6 +353,21 @@ public:
}
/// }
+ /// @name VerboseOutputStream
+ /// }
+
+ /// Replace the current stream for verbose output.
+ void setVerboseOutputStream(raw_ostream &Value);
+
+ /// Replace the current stream for verbose output.
+ void setVerboseOutputStream(std::unique_ptr<raw_ostream> Value);
+
+ /// Get the current stream for verbose output.
+ raw_ostream &getVerboseOutputStream() {
+ return *VerboseOutputStream;
+ }
+
+ /// }
/// @name Target Info
/// {
diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h
index 413134be4cef..f3253d5b40e3 100644
--- a/include/clang/Frontend/CompilerInvocation.h
+++ b/include/clang/Frontend/CompilerInvocation.h
@@ -14,13 +14,14 @@
#include "clang/Basic/FileSystemOptions.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/LangStandard.h"
#include "clang/Frontend/DependencyOutputOptions.h"
#include "clang/Frontend/FrontendOptions.h"
-#include "clang/Frontend/LangStandard.h"
#include "clang/Frontend/MigratorOptions.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/ArrayRef.h"
#include <memory>
#include <string>
@@ -147,13 +148,14 @@ public:
/// Create a compiler invocation from a list of input options.
/// \returns true on success.
///
+ /// \returns false if an error was encountered while parsing the arguments
+ /// and attempts to recover and continue parsing the rest of the arguments.
+ /// The recovery is best-effort and only guarantees that \p Res will end up in
+ /// one of the vaild-to-access (albeit arbitrary) states.
+ ///
/// \param [out] Res - 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 bool CreateFromArgs(CompilerInvocation &Res,
- const char* const *ArgBegin,
- const char* const *ArgEnd,
+ ArrayRef<const char *> CommandLineArgs,
DiagnosticsEngine &Diags);
/// Get the directory where the compiler headers
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index 6c7bc6046f33..89ac20075fa4 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -126,14 +126,7 @@ protected:
bool hasASTFileSupport() const override { return false; }
};
-// Support different interface stub formats this way:
-class GenerateInterfaceYAMLExpV1Action : public GenerateInterfaceStubAction {
-protected:
- std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override;
-};
-
-class GenerateInterfaceTBEExpV1Action : public GenerateInterfaceStubAction {
+class GenerateInterfaceIfsExpV1Action : public GenerateInterfaceStubAction {
protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index a0acb1f066f2..09d83adf579b 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -10,15 +10,16 @@
#define LLVM_CLANG_FRONTEND_FRONTENDOPTIONS_H
#include "clang/AST/ASTDumperUtils.h"
+#include "clang/Basic/LangStandard.h"
#include "clang/Frontend/CommandLineSourceLoc.h"
-#include "clang/Serialization/ModuleFileExtension.h"
#include "clang/Sema/CodeCompleteOptions.h"
+#include "clang/Serialization/ModuleFileExtension.h"
#include "llvm/ADT/StringRef.h"
#include <cassert>
#include <memory>
#include <string>
-#include <vector>
#include <unordered_map>
+#include <vector>
namespace llvm {
@@ -89,8 +90,7 @@ enum ActionKind {
GeneratePCH,
/// Generate Interface Stub Files.
- GenerateInterfaceYAMLExpV1,
- GenerateInterfaceTBEExpV1,
+ GenerateInterfaceIfsExpV1,
/// Only execute frontend initialization.
InitOnly,
@@ -143,35 +143,11 @@ enum ActionKind {
/// The kind of a file that we've been handed as an input.
class InputKind {
private:
- unsigned Lang : 4;
+ Language Lang;
unsigned Fmt : 3;
unsigned Preprocessed : 1;
public:
- /// The language for the input, used to select and validate the language
- /// standard and possible actions.
- enum Language {
- Unknown,
-
- /// Assembly: we accept this only so that we can preprocess it.
- Asm,
-
- /// LLVM IR: we accept this so that we can run the optimizer on it,
- /// and compile it to assembly or object code.
- LLVM_IR,
-
- ///@{ Languages that the frontend can parse and compile.
- C,
- CXX,
- ObjC,
- ObjCXX,
- OpenCL,
- CUDA,
- RenderScript,
- HIP,
- ///@}
- };
-
/// The input file format.
enum Format {
Source,
@@ -179,7 +155,7 @@ public:
Precompiled
};
- constexpr InputKind(Language L = Unknown, Format F = Source,
+ constexpr InputKind(Language L = Language::Unknown, Format F = Source,
bool PP = false)
: Lang(L), Fmt(F), Preprocessed(PP) {}
@@ -188,10 +164,12 @@ public:
bool isPreprocessed() const { return Preprocessed; }
/// Is the input kind fully-unknown?
- bool isUnknown() const { return Lang == Unknown && Fmt == Source; }
+ bool isUnknown() const { return Lang == Language::Unknown && Fmt == Source; }
/// Is the language of the input some dialect of Objective-C?
- bool isObjectiveC() const { return Lang == ObjC || Lang == ObjCXX; }
+ bool isObjectiveC() const {
+ return Lang == Language::ObjC || Lang == Language::ObjCXX;
+ }
InputKind getPreprocessed() const {
return InputKind(getLanguage(), getFormat(), true);
@@ -451,6 +429,9 @@ public:
/// Filename to write statistics to.
std::string StatsFile;
+ /// Minimum time granularity (in microseconds) traced by time profiler.
+ unsigned TimeTraceGranularity;
+
public:
FrontendOptions()
: DisableFree(false), RelocatablePCH(false), ShowHelp(false),
@@ -461,12 +442,12 @@ public:
UseGlobalModuleIndex(true), GenerateGlobalModuleIndex(true),
ASTDumpDecls(false), ASTDumpLookups(false),
BuildingImplicitModule(false), ModulesEmbedAllFiles(false),
- IncludeTimestamps(true) {}
+ IncludeTimestamps(true), TimeTraceGranularity(500) {}
/// getInputKindForExtension - Return the appropriate input kind for a file
- /// extension. For example, "c" would return InputKind::C.
+ /// extension. For example, "c" would return Language::C.
///
- /// \return The input kind for the extension, or InputKind::Unknown if the
+ /// \return The input kind for the extension, or Language::Unknown if the
/// extension is not recognized.
static InputKind getInputKindForExtension(StringRef Extension);
};
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
index 74e563218c31..0f9b17ee5089 100644
--- a/include/clang/Frontend/Utils.h
+++ b/include/clang/Frontend/Utils.h
@@ -99,11 +99,11 @@ public:
/// Return true if system files should be passed to sawDependency().
virtual bool needSystemDependencies() { return false; }
- // implementation detail
/// Add a dependency \p Filename if it has not been seen before and
/// sawDependency() returns true.
- void maybeAddDependency(StringRef Filename, bool FromModule, bool IsSystem,
- bool IsModuleFile, bool IsMissing);
+ virtual void maybeAddDependency(StringRef Filename, bool FromModule,
+ bool IsSystem, bool IsModuleFile,
+ bool IsMissing);
protected:
/// Return true if the filename was added to the list of dependencies, false
@@ -213,13 +213,18 @@ createChainedIncludesSource(CompilerInstance &CI,
/// createInvocationFromCommandLine - Construct a compiler invocation object for
/// a command line argument vector.
///
+/// \param ShouldRecoverOnErrors - whether we should attempt to return a
+/// non-null (and possibly incorrect) CompilerInvocation if any errors were
+/// encountered. When this flag is false, always return null on errors.
+///
/// \return A CompilerInvocation, or 0 if none was built for the given
/// argument vector.
std::unique_ptr<CompilerInvocation> createInvocationFromCommandLine(
ArrayRef<const char *> Args,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
IntrusiveRefCntPtr<DiagnosticsEngine>(),
- IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = nullptr);
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = nullptr,
+ bool ShouldRecoverOnErrors = false);
/// 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.
diff --git a/include/clang/Index/CodegenNameGenerator.h b/include/clang/Index/CodegenNameGenerator.h
deleted file mode 100644
index 98b3a5de817a..000000000000
--- a/include/clang/Index/CodegenNameGenerator.h
+++ /dev/null
@@ -1,52 +0,0 @@
-//===- CodegenNameGenerator.h - Codegen name generation -------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Determines the name that the symbol will get for code generation.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_INDEX_CODEGENNAMEGENERATOR_H
-#define LLVM_CLANG_INDEX_CODEGENNAMEGENERATOR_H
-
-#include "clang/AST/Mangle.h"
-#include "clang/Basic/LLVM.h"
-#include <memory>
-#include <string>
-#include <vector>
-
-namespace clang {
- class ASTContext;
- class Decl;
-
-namespace index {
-
-class CodegenNameGenerator {
-public:
- explicit CodegenNameGenerator(ASTContext &Ctx);
- ~CodegenNameGenerator();
-
- /// \returns true on failure to produce a name for the given decl, false on
- /// success.
- bool writeName(const Decl *D, raw_ostream &OS);
-
- /// Version of \c writeName function that returns a string.
- std::string getName(const Decl *D);
-
- /// This can return multiple mangled names when applicable, e.g. for C++
- /// constructors/destructors.
- std::vector<std::string> getAllManglings(const Decl *D);
-
-private:
- struct Implementation;
- std::unique_ptr<ASTNameGenerator> Impl;
-};
-
-} // namespace index
-} // namespace clang
-
-#endif // LLVM_CLANG_INDEX_CODEGENNAMEGENERATOR_H
diff --git a/include/clang/Index/IndexDataConsumer.h b/include/clang/Index/IndexDataConsumer.h
index bc1d86696df9..72747821bf54 100644
--- a/include/clang/Index/IndexDataConsumer.h
+++ b/include/clang/Index/IndexDataConsumer.h
@@ -32,7 +32,7 @@ public:
const DeclContext *ContainerDC;
};
- virtual ~IndexDataConsumer() {}
+ virtual ~IndexDataConsumer() = default;
virtual void initialize(ASTContext &Ctx) {}
@@ -41,12 +41,16 @@ public:
/// \returns true to continue indexing, or false to abort.
virtual bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles,
ArrayRef<SymbolRelation> Relations,
- SourceLocation Loc, ASTNodeInfo ASTNode);
+ SourceLocation Loc, ASTNodeInfo ASTNode) {
+ return true;
+ }
/// \returns true to continue indexing, or false to abort.
virtual bool handleMacroOccurence(const IdentifierInfo *Name,
const MacroInfo *MI, SymbolRoleSet Roles,
- SourceLocation Loc);
+ SourceLocation Loc) {
+ return true;
+ }
/// \returns true to continue indexing, or false to abort.
///
@@ -54,8 +58,10 @@ public:
/// For "@import MyMod.SubMod", there will be a call for 'MyMod' with the
/// 'reference' role, and a call for 'SubMod' with the 'declaration' role.
virtual bool handleModuleOccurence(const ImportDecl *ImportD,
- const Module *Mod,
- SymbolRoleSet Roles, SourceLocation Loc);
+ const Module *Mod, SymbolRoleSet Roles,
+ SourceLocation Loc) {
+ return true;
+ }
virtual void finish() {}
};
diff --git a/include/clang/Index/IndexingAction.h b/include/clang/Index/IndexingAction.h
index 9756f3c539e6..9ed2a018f161 100644
--- a/include/clang/Index/IndexingAction.h
+++ b/include/clang/Index/IndexingAction.h
@@ -9,7 +9,9 @@
#ifndef LLVM_CLANG_INDEX_INDEXINGACTION_H
#define LLVM_CLANG_INDEX_INDEXINGACTION_H
+#include "clang/AST/ASTConsumer.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Index/IndexingOptions.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/ArrayRef.h"
@@ -17,6 +19,7 @@
namespace clang {
class ASTContext;
+ class ASTConsumer;
class ASTReader;
class ASTUnit;
class Decl;
@@ -29,32 +32,24 @@ namespace serialization {
namespace index {
class IndexDataConsumer;
-struct IndexingOptions {
- enum class SystemSymbolFilterKind {
- None,
- DeclarationsOnly,
- All,
- };
+/// Creates an ASTConsumer that indexes all symbols (macros and AST decls).
+std::unique_ptr<ASTConsumer> createIndexingASTConsumer(
+ std::shared_ptr<IndexDataConsumer> DataConsumer,
+ const IndexingOptions &Opts, std::shared_ptr<Preprocessor> PP,
+ std::function<bool(const Decl *)> ShouldSkipFunctionBody);
- SystemSymbolFilterKind SystemSymbolFilter
- = SystemSymbolFilterKind::DeclarationsOnly;
- bool IndexFunctionLocals = false;
- bool IndexImplicitInstantiation = false;
- // Whether to index macro definitions in the Preprocesor when preprocessor
- // callback is not available (e.g. after parsing has finished). Note that
- // macro references are not available in Proprocessor.
- bool IndexMacrosInPreprocessor = false;
- // Has no effect if IndexFunctionLocals are false.
- bool IndexParametersInDeclarations = false;
- bool IndexTemplateParameters = false;
-};
+inline std::unique_ptr<ASTConsumer> createIndexingASTConsumer(
+ std::shared_ptr<IndexDataConsumer> DataConsumer,
+ const IndexingOptions &Opts, std::shared_ptr<Preprocessor> PP) {
+ return createIndexingASTConsumer(
+ std::move(DataConsumer), Opts, std::move(PP),
+ /*ShouldSkipFunctionBody=*/[](const Decl *) { return false; });
+}
/// Creates a frontend action that indexes all symbols (macros and AST decls).
-/// \param WrappedAction another frontend action to wrap over or null.
std::unique_ptr<FrontendAction>
createIndexingAction(std::shared_ptr<IndexDataConsumer> DataConsumer,
- IndexingOptions Opts,
- std::unique_ptr<FrontendAction> WrappedAction);
+ const IndexingOptions &Opts);
/// Recursively indexes all decls in the AST.
void indexASTUnit(ASTUnit &Unit, IndexDataConsumer &DataConsumer,
diff --git a/include/clang/Index/IndexingOptions.h b/include/clang/Index/IndexingOptions.h
new file mode 100644
index 000000000000..bbfd6e4a72c6
--- /dev/null
+++ b/include/clang/Index/IndexingOptions.h
@@ -0,0 +1,42 @@
+//===--- IndexingOptions.h - Options for indexing ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_INDEXINGOPTIONS_H
+#define LLVM_CLANG_INDEX_INDEXINGOPTIONS_H
+
+#include "clang/Frontend/FrontendOptions.h"
+#include <memory>
+#include <string>
+
+namespace clang {
+namespace index {
+
+struct IndexingOptions {
+ enum class SystemSymbolFilterKind {
+ None,
+ DeclarationsOnly,
+ All,
+ };
+
+ SystemSymbolFilterKind SystemSymbolFilter =
+ SystemSymbolFilterKind::DeclarationsOnly;
+ bool IndexFunctionLocals = false;
+ bool IndexImplicitInstantiation = false;
+ // Whether to index macro definitions in the Preprocesor when preprocessor
+ // callback is not available (e.g. after parsing has finished). Note that
+ // macro references are not available in Proprocessor.
+ bool IndexMacrosInPreprocessor = false;
+ // Has no effect if IndexFunctionLocals are false.
+ bool IndexParametersInDeclarations = false;
+ bool IndexTemplateParameters = false;
+};
+
+} // namespace index
+} // namespace clang
+
+#endif // LLVM_CLANG_INDEX_INDEXINGOPTIONS_H
diff --git a/include/clang/Lex/DependencyDirectivesSourceMinimizer.h b/include/clang/Lex/DependencyDirectivesSourceMinimizer.h
index 41641078afe4..d832df6b6146 100644
--- a/include/clang/Lex/DependencyDirectivesSourceMinimizer.h
+++ b/include/clang/Lex/DependencyDirectivesSourceMinimizer.h
@@ -38,6 +38,7 @@ enum TokenKind {
pp_undef,
pp_import,
pp_pragma_import,
+ pp_pragma_once,
pp_include_next,
pp_if,
pp_ifdef,
@@ -46,6 +47,9 @@ enum TokenKind {
pp_else,
pp_endif,
decl_at_import,
+ cxx_export_decl,
+ cxx_module_decl,
+ cxx_import_decl,
pp_eof,
};
@@ -62,6 +66,24 @@ struct Token {
Token(TokenKind K, int Offset) : K(K), Offset(Offset) {}
};
+/// Simplified token range to track the range of a potentially skippable PP
+/// directive.
+struct SkippedRange {
+ /// Offset into the output byte stream of where the skipped directive begins.
+ int Offset;
+
+ /// The number of bytes that can be skipped before the preprocessing must
+ /// resume.
+ int Length;
+};
+
+/// Computes the potential source ranges that can be skipped by the preprocessor
+/// when skipping a directive like #if, #ifdef or #elsif.
+///
+/// \returns false on success, true on error.
+bool computeSkippedRanges(ArrayRef<Token> Input,
+ llvm::SmallVectorImpl<SkippedRange> &Range);
+
} // end namespace minimize_source_to_dependency_directives
/// Minimize the input down to the preprocessor directives that might have
diff --git a/include/clang/Lex/DirectoryLookup.h b/include/clang/Lex/DirectoryLookup.h
index 7c556ac35175..d526319a68c6 100644
--- a/include/clang/Lex/DirectoryLookup.h
+++ b/include/clang/Lex/DirectoryLookup.h
@@ -36,14 +36,17 @@ public:
LT_HeaderMap
};
private:
- union { // This union is discriminated by isHeaderMap.
+ union DLU { // This union is discriminated by isHeaderMap.
/// Dir - This is the actual directory that we're referring to for a normal
/// directory or a framework.
- const DirectoryEntry *Dir;
+ DirectoryEntryRef Dir;
/// Map - This is the HeaderMap if this is a headermap lookup.
///
const HeaderMap *Map;
+
+ DLU(DirectoryEntryRef Dir) : Dir(Dir) {}
+ DLU(const HeaderMap *Map) : Map(Map) {}
} u;
/// DirCharacteristic - The type of directory this is: this is an instance of
@@ -62,24 +65,18 @@ private:
unsigned SearchedAllModuleMaps : 1;
public:
- /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of
- /// 'dir'.
- DirectoryLookup(const DirectoryEntry *dir, SrcMgr::CharacteristicKind DT,
+ /// This ctor *does not take ownership* of 'Dir'.
+ DirectoryLookup(DirectoryEntryRef Dir, SrcMgr::CharacteristicKind DT,
bool isFramework)
- : DirCharacteristic(DT),
- LookupType(isFramework ? LT_Framework : LT_NormalDir),
- IsIndexHeaderMap(false), SearchedAllModuleMaps(false) {
- u.Dir = dir;
- }
+ : u(Dir), DirCharacteristic(DT),
+ LookupType(isFramework ? LT_Framework : LT_NormalDir),
+ IsIndexHeaderMap(false), SearchedAllModuleMaps(false) {}
- /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of
- /// 'map'.
- DirectoryLookup(const HeaderMap *map, SrcMgr::CharacteristicKind DT,
+ /// This ctor *does not take ownership* of 'Map'.
+ DirectoryLookup(const HeaderMap *Map, SrcMgr::CharacteristicKind DT,
bool isIndexHeaderMap)
- : DirCharacteristic(DT), LookupType(LT_HeaderMap),
- IsIndexHeaderMap(isIndexHeaderMap), SearchedAllModuleMaps(false) {
- u.Map = map;
- }
+ : u(Map), DirCharacteristic(DT), LookupType(LT_HeaderMap),
+ IsIndexHeaderMap(isIndexHeaderMap), SearchedAllModuleMaps(false) {}
/// getLookupType - Return the kind of directory lookup that this is: either a
/// normal directory, a framework path, or a HeaderMap.
@@ -92,13 +89,17 @@ public:
/// getDir - Return the directory that this entry refers to.
///
const DirectoryEntry *getDir() const {
- return isNormalDir() ? u.Dir : nullptr;
+ return isNormalDir() ? &u.Dir.getDirEntry() : nullptr;
}
/// getFrameworkDir - Return the directory that this framework refers to.
///
const DirectoryEntry *getFrameworkDir() const {
- return isFramework() ? u.Dir : nullptr;
+ return isFramework() ? &u.Dir.getDirEntry() : nullptr;
+ }
+
+ Optional<DirectoryEntryRef> getFrameworkDirRef() const {
+ return isFramework() ? Optional<DirectoryEntryRef>(u.Dir) : None;
}
/// getHeaderMap - Return the directory that this entry refers to.
@@ -176,27 +177,20 @@ public:
/// \param [out] MappedName if this is a headermap which maps the filename to
/// a framework include ("Foo.h" -> "Foo/Foo.h"), set the new name to this
/// vector and point Filename to it.
- const FileEntry *LookupFile(StringRef &Filename, HeaderSearch &HS,
- SourceLocation IncludeLoc,
- SmallVectorImpl<char> *SearchPath,
- SmallVectorImpl<char> *RelativePath,
- Module *RequestingModule,
- ModuleMap::KnownHeader *SuggestedModule,
- bool &InUserSpecifiedSystemFramework,
- bool &IsFrameworkFound,
- bool &HasBeenMapped,
- SmallVectorImpl<char> &MappedName) const;
+ Optional<FileEntryRef>
+ LookupFile(StringRef &Filename, HeaderSearch &HS, SourceLocation IncludeLoc,
+ SmallVectorImpl<char> *SearchPath,
+ SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
+ ModuleMap::KnownHeader *SuggestedModule,
+ bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound,
+ bool &IsInHeaderMap, SmallVectorImpl<char> &MappedName) const;
private:
- const FileEntry *DoFrameworkLookup(
- StringRef Filename, HeaderSearch &HS,
- SmallVectorImpl<char> *SearchPath,
- SmallVectorImpl<char> *RelativePath,
- Module *RequestingModule,
+ Optional<FileEntryRef> DoFrameworkLookup(
+ StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath,
+ SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
ModuleMap::KnownHeader *SuggestedModule,
- bool &InUserSpecifiedSystemFramework,
- bool &IsFrameworkFound) const;
-
+ bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound) const;
};
} // end namespace clang
diff --git a/include/clang/Lex/HeaderMap.h b/include/clang/Lex/HeaderMap.h
index eca8755d4525..accb061e51ba 100644
--- a/include/clang/Lex/HeaderMap.h
+++ b/include/clang/Lex/HeaderMap.h
@@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_LEX_HEADERMAP_H
#define LLVM_CLANG_LEX_HEADERMAP_H
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/Compiler.h"
@@ -21,8 +22,6 @@
namespace clang {
-class FileEntry;
-class FileManager;
struct HMapBucket;
struct HMapHeader;
@@ -78,7 +77,7 @@ public:
/// NULL and the file is found, RawPath will be set to the raw path at which
/// the file was found in the file system. For example, for a search path
/// ".." and a filename "../file.h" this would be "../../file.h".
- const FileEntry *LookupFile(StringRef Filename, FileManager &FM) const;
+ Optional<FileEntryRef> LookupFile(StringRef Filename, FileManager &FM) const;
using HeaderMapImpl::lookupFilename;
using HeaderMapImpl::getFileName;
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index c5e66242444a..0d20dafe2cb1 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -250,12 +250,6 @@ class HeaderSearch {
/// Entity used to look up stored header file information.
ExternalHeaderFileInfoSource *ExternalSource = nullptr;
- // Various statistics we track for performance analysis.
- unsigned NumIncluded = 0;
- unsigned NumMultiIncludeFileOptzn = 0;
- unsigned NumFrameworkLookups = 0;
- unsigned NumSubFrameworkLookups = 0;
-
public:
HeaderSearch(std::shared_ptr<HeaderSearchOptions> HSOpts,
SourceManager &SourceMgr, DiagnosticsEngine &Diags,
@@ -395,7 +389,7 @@ public:
/// found in any of searched SearchDirs. Will be set to false if a framework
/// is found only through header maps. Doesn't guarantee the requested file is
/// found.
- const FileEntry *LookupFile(
+ Optional<FileEntryRef> LookupFile(
StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
@@ -410,7 +404,7 @@ public:
/// within ".../Carbon.framework/Headers/Carbon.h", check to see if
/// HIToolbox is a subframework within Carbon.framework. If so, return
/// the FileEntry for the designated file, otherwise return null.
- const FileEntry *LookupSubframeworkHeader(
+ Optional<FileEntryRef> LookupSubframeworkHeader(
StringRef Filename, const FileEntry *ContextFileEnt,
SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule);
@@ -544,8 +538,6 @@ public:
const FileEntry *lookupModuleMapFile(const DirectoryEntry *Dir,
bool IsFramework);
- void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; }
-
/// Determine whether there is a module map that may map the header
/// with the given file name to a (sub)module.
/// Always returns false if modules are disabled.
@@ -649,7 +641,7 @@ private:
/// Look up the file with the specified name and determine its owning
/// module.
- const FileEntry *
+ Optional<FileEntryRef>
getFileAndSuggestModule(StringRef FileName, SourceLocation IncludeLoc,
const DirectoryEntry *Dir, bool IsSystemHeaderDir,
Module *RequestingModule,
diff --git a/include/clang/Lex/HeaderSearchOptions.h b/include/clang/Lex/HeaderSearchOptions.h
index ed128bce485f..5c19a41986b5 100644
--- a/include/clang/Lex/HeaderSearchOptions.h
+++ b/include/clang/Lex/HeaderSearchOptions.h
@@ -11,6 +11,7 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/CachedHashString.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringRef.h"
#include <cstdint>
@@ -195,6 +196,10 @@ public:
/// Whether to validate system input files when a module is loaded.
unsigned ModulesValidateSystemHeaders : 1;
+ // Whether the content of input files should be hashed and used to
+ // validate consistency.
+ unsigned ValidateASTInputFilesContent : 1;
+
/// Whether the module includes debug information (-gmodules).
unsigned UseDebugInfo : 1;
@@ -202,14 +207,23 @@ public:
unsigned ModulesHashContent : 1;
+ /// Whether we should include all things that could impact the module in the
+ /// hash.
+ ///
+ /// This includes things like the full header search path, and enabled
+ /// diagnostics.
+ unsigned ModulesStrictContextHash : 1;
+
HeaderSearchOptions(StringRef _Sysroot = "/")
: Sysroot(_Sysroot), ModuleFormat("raw"), DisableModuleHash(false),
ImplicitModuleMaps(false), ModuleMapFileHomeIsCwd(false),
UseBuiltinIncludes(true), UseStandardSystemIncludes(true),
UseStandardCXXIncludes(true), UseLibcxx(false), Verbose(false),
ModulesValidateOncePerBuildSession(false),
- ModulesValidateSystemHeaders(false), UseDebugInfo(false),
- ModulesValidateDiagnosticOptions(true), ModulesHashContent(false) {}
+ ModulesValidateSystemHeaders(false),
+ ValidateASTInputFilesContent(false), UseDebugInfo(false),
+ ModulesValidateDiagnosticOptions(true), ModulesHashContent(false),
+ ModulesStrictContextHash(false) {}
/// AddPath - Add the \p Path path to the specified \p Group list.
void AddPath(StringRef Path, frontend::IncludeDirGroup Group,
@@ -233,6 +247,15 @@ public:
}
};
+inline llvm::hash_code hash_value(const HeaderSearchOptions::Entry &E) {
+ return llvm::hash_combine(E.Path, E.Group, E.IsFramework, E.IgnoreSysRoot);
+}
+
+inline llvm::hash_code
+hash_value(const HeaderSearchOptions::SystemHeaderPrefix &SHP) {
+ return llvm::hash_combine(SHP.Prefix, SHP.IsSystemHeader);
+}
+
} // namespace clang
#endif // LLVM_CLANG_LEX_HEADERSEARCHOPTIONS_H
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
index 69cfe62e4bdb..97a222f4a703 100644
--- a/include/clang/Lex/Lexer.h
+++ b/include/clang/Lex/Lexer.h
@@ -265,6 +265,21 @@ public:
/// Return the current location in the buffer.
const char *getBufferLocation() const { return BufferPtr; }
+ /// Returns the current lexing offset.
+ unsigned getCurrentBufferOffset() {
+ assert(BufferPtr >= BufferStart && "Invalid buffer state");
+ return BufferPtr - BufferStart;
+ }
+
+ /// Skip over \p NumBytes bytes.
+ ///
+ /// If the skip is successful, the next token will be lexed from the new
+ /// offset. The lexer also assumes that we skipped to the start of the line.
+ ///
+ /// \returns true if the skip failed (new offset would have been past the
+ /// end of the buffer), false otherwise.
+ bool skipOver(unsigned NumBytes);
+
/// Stringify - Convert the specified string into a C string by i) escaping
/// '\\' and " characters and ii) replacing newline character(s) with "\\n".
/// If Charify is true, this escapes the ' character instead of ".
diff --git a/include/clang/Lex/MacroArgs.h b/include/clang/Lex/MacroArgs.h
index 8806f2d8c656..59676c30e0a5 100644
--- a/include/clang/Lex/MacroArgs.h
+++ b/include/clang/Lex/MacroArgs.h
@@ -48,10 +48,6 @@ class MacroArgs final
/// stream.
std::vector<std::vector<Token> > PreExpArgTokens;
- /// StringifiedArgs - This contains arguments in 'stringified' form. If the
- /// stringified form of an argument has not yet been computed, this is empty.
- std::vector<Token> StringifiedArgs;
-
/// ArgCache - This is a linked list of MacroArgs objects that the
/// Preprocessor owns which we use to avoid thrashing malloc/free.
MacroArgs *ArgCache;
@@ -94,12 +90,6 @@ public:
const std::vector<Token> &
getPreExpArgument(unsigned Arg, Preprocessor &PP);
- /// getStringifiedArgument - Compute, cache, and return the specified argument
- /// that has been 'stringified' as required by the # operator.
- const Token &getStringifiedArgument(unsigned ArgNo, Preprocessor &PP,
- SourceLocation ExpansionLocStart,
- SourceLocation ExpansionLocEnd);
-
/// getNumMacroArguments - Return the number of arguments the invoked macro
/// expects.
unsigned getNumMacroArguments() const { return NumMacroArgs; }
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index f3f3796b1a30..1edcb567de66 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -57,10 +57,9 @@ public:
/// \param FilenameTok The file name token in \#include "FileName" directive
/// or macro expanded file name token from \#include MACRO(PARAMS) directive.
/// Note that FilenameTok contains corresponding quotes/angles symbols.
- virtual void FileSkipped(const FileEntry &SkippedFile,
+ virtual void FileSkipped(const FileEntryRef &SkippedFile,
const Token &FilenameTok,
- SrcMgr::CharacteristicKind FileType) {
- }
+ SrcMgr::CharacteristicKind FileType) {}
/// Callback invoked whenever an inclusion directive results in a
/// file-not-found error.
@@ -308,7 +307,7 @@ public:
/// Hook called when a '__has_include' or '__has_include_next' directive is
/// read.
virtual void HasInclude(SourceLocation Loc, StringRef FileName, bool IsAngled,
- const FileEntry *File,
+ Optional<FileEntryRef> File,
SrcMgr::CharacteristicKind FileType) {}
/// Hook called when a source range is skipped.
@@ -390,8 +389,7 @@ public:
Second->FileChanged(Loc, Reason, FileType, PrevFID);
}
- void FileSkipped(const FileEntry &SkippedFile,
- const Token &FilenameTok,
+ void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,
SrcMgr::CharacteristicKind FileType) override {
First->FileSkipped(SkippedFile, FilenameTok, FileType);
Second->FileSkipped(SkippedFile, FilenameTok, FileType);
@@ -491,7 +489,7 @@ public:
}
void HasInclude(SourceLocation Loc, StringRef FileName, bool IsAngled,
- const FileEntry *File,
+ Optional<FileEntryRef> File,
SrcMgr::CharacteristicKind FileType) override {
First->HasInclude(Loc, FileName, IsAngled, File, FileType);
Second->HasInclude(Loc, FileName, IsAngled, File, FileType);
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index f65b0cda462f..1bdd2be04c0e 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -28,6 +28,7 @@
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/ModuleMap.h"
#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/PreprocessorExcludedConditionalDirectiveSkipMapping.h"
#include "clang/Lex/Token.h"
#include "clang/Lex/TokenLexer.h"
#include "llvm/ADT/ArrayRef.h"
@@ -370,9 +371,9 @@ class Preprocessor {
/// it expects a '.' or ';'.
bool ModuleImportExpectsIdentifier = false;
- /// The source location of the currently-active
+ /// The identifier and source location of the currently-active
/// \#pragma clang arc_cf_code_audited begin.
- SourceLocation PragmaARCCFCodeAuditedLoc;
+ std::pair<IdentifierInfo *, SourceLocation> PragmaARCCFCodeAuditedInfo;
/// The source location of the currently-active
/// \#pragma clang assume_nonnull begin.
@@ -994,7 +995,7 @@ public:
PPCallbacks *getPPCallbacks() const { return Callbacks.get(); }
void addPPCallbacks(std::unique_ptr<PPCallbacks> C) {
if (Callbacks)
- C = llvm::make_unique<PPChainedCallbacks>(std::move(C),
+ C = std::make_unique<PPChainedCallbacks>(std::move(C),
std::move(Callbacks));
Callbacks = std::move(C);
}
@@ -1471,7 +1472,7 @@ public:
if (LexLevel) {
// It's not correct in general to enter caching lex mode while in the
// middle of a nested lexing action.
- auto TokCopy = llvm::make_unique<Token[]>(1);
+ auto TokCopy = std::make_unique<Token[]>(1);
TokCopy[0] = Tok;
EnterTokenStream(std::move(TokCopy), 1, true, IsReinject);
} else {
@@ -1601,14 +1602,16 @@ public:
/// arc_cf_code_audited begin.
///
/// Returns an invalid location if there is no such pragma active.
- SourceLocation getPragmaARCCFCodeAuditedLoc() const {
- return PragmaARCCFCodeAuditedLoc;
+ std::pair<IdentifierInfo *, SourceLocation>
+ getPragmaARCCFCodeAuditedInfo() const {
+ return PragmaARCCFCodeAuditedInfo;
}
/// Set the location of the currently-active \#pragma clang
/// arc_cf_code_audited begin. An invalid location ends the pragma.
- void setPragmaARCCFCodeAuditedLoc(SourceLocation Loc) {
- PragmaARCCFCodeAuditedLoc = Loc;
+ void setPragmaARCCFCodeAuditedInfo(IdentifierInfo *Ident,
+ SourceLocation Loc) {
+ PragmaARCCFCodeAuditedInfo = {Ident, Loc};
}
/// The location of the currently-active \#pragma clang
@@ -1949,17 +1952,15 @@ public:
/// Given a "foo" or \<foo> reference, look up the indicated file.
///
- /// Returns null on failure. \p isAngled indicates whether the file
+ /// Returns None on failure. \p isAngled indicates whether the file
/// reference is for system \#include's or not (i.e. using <> instead of "").
- const FileEntry *LookupFile(SourceLocation FilenameLoc, StringRef Filename,
- bool isAngled, const DirectoryLookup *FromDir,
- const FileEntry *FromFile,
- const DirectoryLookup *&CurDir,
- SmallVectorImpl<char> *SearchPath,
- SmallVectorImpl<char> *RelativePath,
- ModuleMap::KnownHeader *SuggestedModule,
- bool *IsMapped, bool *IsFrameworkFound,
- bool SkipCache = false);
+ Optional<FileEntryRef>
+ LookupFile(SourceLocation FilenameLoc, StringRef Filename, bool isAngled,
+ const DirectoryLookup *FromDir, const FileEntry *FromFile,
+ const DirectoryLookup *&CurDir, SmallVectorImpl<char> *SearchPath,
+ SmallVectorImpl<char> *RelativePath,
+ ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped,
+ bool *IsFrameworkFound, bool SkipCache = false);
/// Get the DirectoryLookup structure used to find the current
/// FileEntry, if CurLexer is non-null and if applicable.
@@ -2202,6 +2203,15 @@ private:
}
};
+ Optional<FileEntryRef> LookupHeaderIncludeOrImport(
+ const DirectoryLookup *&CurDir, StringRef Filename,
+ SourceLocation FilenameLoc, CharSourceRange FilenameRange,
+ const Token &FilenameTok, bool &IsFrameworkFound, bool IsImportDecl,
+ bool &IsMapped, const DirectoryLookup *LookupFrom,
+ const FileEntry *LookupFromFile, StringRef LookupFilename,
+ SmallVectorImpl<char> &RelativePath, SmallVectorImpl<char> &SearchPath,
+ ModuleMap::KnownHeader &SuggestedModule, bool isAngled);
+
// File inclusion.
void HandleIncludeDirective(SourceLocation HashLoc, Token &Tok,
const DirectoryLookup *LookupFrom = nullptr,
@@ -2313,6 +2323,15 @@ public:
/// A macro is used, update information about macros that need unused
/// warnings.
void markMacroAsUsed(MacroInfo *MI);
+
+private:
+ Optional<unsigned>
+ getSkippedRangeForExcludedConditionalBlock(SourceLocation HashLoc);
+
+ /// Contains the currently active skipped range mappings for skipping excluded
+ /// conditional directives.
+ ExcludedPreprocessorDirectiveSkipMapping
+ *ExcludedConditionalDirectiveSkipMappings;
};
/// Abstract base class that describes a handler that will receive
diff --git a/include/clang/Lex/PreprocessorExcludedConditionalDirectiveSkipMapping.h b/include/clang/Lex/PreprocessorExcludedConditionalDirectiveSkipMapping.h
new file mode 100644
index 000000000000..893b7ba7a9f5
--- /dev/null
+++ b/include/clang/Lex/PreprocessorExcludedConditionalDirectiveSkipMapping.h
@@ -0,0 +1,31 @@
+//===- PreprocessorExcludedConditionalDirectiveSkipMapping.h - --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LEX_PREPROCESSOR_EXCLUDED_COND_DIRECTIVE_SKIP_MAPPING_H
+#define LLVM_CLANG_LEX_PREPROCESSOR_EXCLUDED_COND_DIRECTIVE_SKIP_MAPPING_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+namespace clang {
+
+/// A mapping from an offset into a buffer to the number of bytes that can be
+/// skipped by the preprocessor when skipping over excluded conditional
+/// directive ranges.
+using PreprocessorSkippedRangeMapping = llvm::DenseMap<unsigned, unsigned>;
+
+/// The datastructure that holds the mapping between the active memory buffers
+/// and the individual skip mappings.
+using ExcludedPreprocessorDirectiveSkipMapping =
+ llvm::DenseMap<const llvm::MemoryBuffer *,
+ const PreprocessorSkippedRangeMapping *>;
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_LEX_PREPROCESSOR_EXCLUDED_COND_DIRECTIVE_SKIP_MAPPING_H
diff --git a/include/clang/Lex/PreprocessorOptions.h b/include/clang/Lex/PreprocessorOptions.h
index 1480548c7fbe..344afa894172 100644
--- a/include/clang/Lex/PreprocessorOptions.h
+++ b/include/clang/Lex/PreprocessorOptions.h
@@ -10,6 +10,7 @@
#define LLVM_CLANG_LEX_PREPROCESSOROPTIONS_H_
#include "clang/Basic/LLVM.h"
+#include "clang/Lex/PreprocessorExcludedConditionalDirectiveSkipMapping.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include <memory>
@@ -142,6 +143,9 @@ public:
/// compiler invocation and its buffers will be reused.
bool RetainRemappedFileBuffers = false;
+ /// When enabled, excluded conditional blocks retain in the main file.
+ bool RetainExcludedConditionalBlocks = false;
+
/// The Objective-C++ ARC standard library that we should support,
/// by providing appropriate definitions to retrofit the standard library
/// with support for lifetime-qualified pointers.
@@ -169,6 +173,17 @@ public:
/// build it again.
std::shared_ptr<FailedModulesSet> FailedModules;
+ /// Contains the currently active skipped range mappings for skipping excluded
+ /// conditional directives.
+ ///
+ /// The pointer is passed to the Preprocessor when it's constructed. The
+ /// pointer is unowned, the client is responsible for its lifetime.
+ ExcludedPreprocessorDirectiveSkipMapping
+ *ExcludedConditionalDirectiveSkipMappings = nullptr;
+
+ /// Set up preprocessor for RunAnalysis action.
+ bool SetUpStaticAnalyzer = false;
+
public:
PreprocessorOptions() : PrecompiledPreambleBytes(0, false) {}
@@ -201,6 +216,7 @@ public:
RetainRemappedFileBuffers = true;
PrecompiledPreambleBytes.first = 0;
PrecompiledPreambleBytes.second = false;
+ RetainExcludedConditionalBlocks = false;
}
};
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 7c67c35f615a..52d159062cd7 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -766,6 +766,22 @@ private:
Tok.setAnnotationValue(T.getAsOpaquePtr());
}
+ static NamedDecl *getNonTypeAnnotation(const Token &Tok) {
+ return static_cast<NamedDecl*>(Tok.getAnnotationValue());
+ }
+
+ static void setNonTypeAnnotation(Token &Tok, NamedDecl *ND) {
+ Tok.setAnnotationValue(ND);
+ }
+
+ static IdentifierInfo *getIdentifierAnnotation(const Token &Tok) {
+ return static_cast<IdentifierInfo*>(Tok.getAnnotationValue());
+ }
+
+ static void setIdentifierAnnotation(Token &Tok, IdentifierInfo *ND) {
+ Tok.setAnnotationValue(ND);
+ }
+
/// Read an already-translated primary expression out of an annotation
/// token.
static ExprResult getExprAnnotation(const Token &Tok) {
@@ -799,8 +815,7 @@ private:
/// Annotation was successful.
ANK_Success
};
- AnnotatedNameKind TryAnnotateName(bool IsAddressOfOperand,
- CorrectionCandidateCallback *CCC = nullptr);
+ AnnotatedNameKind TryAnnotateName(CorrectionCandidateCallback *CCC = nullptr);
/// Push a tok::annot_cxxscope token onto the token stream.
void AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation);
@@ -972,7 +987,7 @@ private:
};
/// Consume any extra semi-colons until the end of the line.
- void ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST = TST_unspecified);
+ void ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST T = TST_unspecified);
/// Return false if the next token is an identifier. An 'expected identifier'
/// error is emitted otherwise.
@@ -2107,12 +2122,13 @@ private:
DeclGroupPtrTy ParseDeclaration(DeclaratorContext Context,
SourceLocation &DeclEnd,
- ParsedAttributesWithRange &attrs);
- DeclGroupPtrTy ParseSimpleDeclaration(DeclaratorContext Context,
- SourceLocation &DeclEnd,
- ParsedAttributesWithRange &attrs,
- bool RequireSemi,
- ForRangeInit *FRI = nullptr);
+ ParsedAttributesWithRange &attrs,
+ SourceLocation *DeclSpecStart = nullptr);
+ DeclGroupPtrTy
+ ParseSimpleDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd,
+ ParsedAttributesWithRange &attrs, bool RequireSemi,
+ ForRangeInit *FRI = nullptr,
+ SourceLocation *DeclSpecStart = nullptr);
bool MightBeDeclarator(DeclaratorContext Context);
DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context,
SourceLocation *DeclEnd = nullptr,
@@ -2160,7 +2176,7 @@ private:
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS, DeclSpecContext DSC);
void ParseEnumBody(SourceLocation StartLoc, Decl *TagDecl);
- void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType,
+ void ParseStructUnionBody(SourceLocation StartLoc, DeclSpec::TST TagType,
Decl *TagDecl);
void ParseStructDeclaration(
@@ -2833,6 +2849,17 @@ private:
DeclGroupPtrTy ParseOMPDeclareSimdClauses(DeclGroupPtrTy Ptr,
CachedTokens &Toks,
SourceLocation Loc);
+ /// Parses OpenMP context selectors and calls \p Callback for each
+ /// successfully parsed context selector.
+ bool parseOpenMPContextSelectors(
+ SourceLocation Loc,
+ llvm::function_ref<
+ void(SourceRange, const Sema::OpenMPDeclareVariantCtsSelectorData &)>
+ Callback);
+
+ /// Parse clauses for '#pragma omp declare variant'.
+ void ParseOMPDeclareVariantClauses(DeclGroupPtrTy Ptr, CachedTokens &Toks,
+ SourceLocation Loc);
/// Parse clauses for '#pragma omp declare target'.
DeclGroupPtrTy ParseOMPDeclareTargetClauses();
/// Parse '#pragma omp end declare target'.
@@ -2926,7 +2953,8 @@ public:
/// Parses simple expression in parens for single-expression clauses of OpenMP
/// constructs.
/// \param RLoc Returned location of right paren.
- ExprResult ParseOpenMPParensExpr(StringRef ClauseName, SourceLocation &RLoc);
+ ExprResult ParseOpenMPParensExpr(StringRef ClauseName, SourceLocation &RLoc,
+ bool IsAddressOfOperand = false);
/// Data used for parsing list of variables in OpenMP clauses.
struct OpenMPVarListDataTy {
diff --git a/include/clang/Rewrite/Core/Rewriter.h b/include/clang/Rewrite/Core/Rewriter.h
index 84c5ac3d72ee..c89015e40558 100644
--- a/include/clang/Rewrite/Core/Rewriter.h
+++ b/include/clang/Rewrite/Core/Rewriter.h
@@ -46,6 +46,17 @@ public:
/// If true and removing some text leaves a blank line
/// also remove the empty line (false by default).
+ ///
+ /// FIXME: This sometimes corrupts the file's rewrite buffer due to
+ /// incorrect indexing in the implementation (see the FIXME in
+ /// clang::RewriteBuffer::RemoveText). Moreover, it's inefficient because
+ /// it must scan the buffer from the beginning to find the start of the
+ /// line. When feasible, it's better for the caller to check for a blank
+ /// line and then, if found, expand the removal range to include it.
+ /// Checking for a blank line is easy if, for example, the caller can
+ /// guarantee this is the first edit of a line. In that case, it can just
+ /// scan before and after the removal range until the next newline or
+ /// begin/end of the input.
bool RemoveLineIfEmpty = false;
RewriteOptions() {}
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index 96aadeac2ba3..a97a7181f7d5 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -71,6 +71,30 @@ class Sema;
OCD_ViableCandidates
};
+ /// The parameter ordering that will be used for the candidate. This is
+ /// used to represent C++20 binary operator rewrites that reverse the order
+ /// of the arguments. If the parameter ordering is Reversed, the Args list is
+ /// reversed (but obviously the ParamDecls for the function are not).
+ ///
+ /// After forming an OverloadCandidate with reversed parameters, the list
+ /// of conversions will (as always) be indexed by argument, so will be
+ /// in reverse parameter order.
+ enum class OverloadCandidateParamOrder : char { Normal, Reversed };
+
+ /// The kinds of rewrite we perform on overload candidates. Note that the
+ /// values here are chosen to serve as both bitflags and as a rank (lower
+ /// values are preferred by overload resolution).
+ enum OverloadCandidateRewriteKind : unsigned {
+ /// Candidate is not a rewritten candidate.
+ CRK_None = 0x0,
+
+ /// Candidate is a rewritten candidate with a different operator name.
+ CRK_DifferentOperator = 0x1,
+
+ /// Candidate is a rewritten candidate with a reversed order of parameters.
+ CRK_Reversed = 0x2,
+ };
+
/// ImplicitConversionKind - The kind of implicit conversion used to
/// convert an argument to a parameter's type. The enumerator values
/// match with the table titled 'Conversions' in [over.ics.scs] and are listed
@@ -757,7 +781,8 @@ class Sema;
CXXConversionDecl *Surrogate;
/// The conversion sequences used to convert the function arguments
- /// to the function parameters.
+ /// to the function parameters. Note that these are indexed by argument,
+ /// so may not match the parameter order of Function.
ConversionSequenceList Conversions;
/// The FixIt hints which can be used to fix the Bad candidate.
@@ -783,6 +808,9 @@ class Sema;
/// True if the candidate was found using ADL.
CallExpr::ADLCallKind IsADLCandidate : 1;
+ /// Whether this is a rewritten candidate, and if so, of what kind?
+ OverloadCandidateRewriteKind RewriteKind : 2;
+
/// FailureKind - The reason why this candidate is not viable.
/// Actually an OverloadFailureKind.
unsigned char FailureKind;
@@ -826,10 +854,10 @@ class Sema;
unsigned getNumParams() const {
if (IsSurrogate) {
- auto STy = Surrogate->getConversionType();
+ QualType STy = Surrogate->getConversionType();
while (STy->isPointerType() || STy->isReferenceType())
STy = STy->getPointeeType();
- return STy->getAs<FunctionProtoType>()->getNumParams();
+ return STy->castAs<FunctionProtoType>()->getNumParams();
}
if (Function)
return Function->getNumParams();
@@ -838,7 +866,8 @@ class Sema;
private:
friend class OverloadCandidateSet;
- OverloadCandidate() : IsADLCandidate(CallExpr::NotADL) {}
+ OverloadCandidate()
+ : IsADLCandidate(CallExpr::NotADL), RewriteKind(CRK_None) {}
};
/// OverloadCandidateSet - A set of overload candidates, used in C++
@@ -867,9 +896,54 @@ class Sema;
CSK_InitByConstructor,
};
+ /// Information about operator rewrites to consider when adding operator
+ /// functions to a candidate set.
+ struct OperatorRewriteInfo {
+ OperatorRewriteInfo()
+ : OriginalOperator(OO_None), AllowRewrittenCandidates(false) {}
+ OperatorRewriteInfo(OverloadedOperatorKind Op, bool AllowRewritten)
+ : OriginalOperator(Op), AllowRewrittenCandidates(AllowRewritten) {}
+
+ /// The original operator as written in the source.
+ OverloadedOperatorKind OriginalOperator;
+ /// Whether we should include rewritten candidates in the overload set.
+ bool AllowRewrittenCandidates;
+
+ /// Would use of this function result in a rewrite using a different
+ /// operator?
+ bool isRewrittenOperator(const FunctionDecl *FD) {
+ return OriginalOperator &&
+ FD->getDeclName().getCXXOverloadedOperator() != OriginalOperator;
+ }
+
+ bool isAcceptableCandidate(const FunctionDecl *FD) {
+ return AllowRewrittenCandidates || !isRewrittenOperator(FD);
+ }
+
+ /// Determine the kind of rewrite that should be performed for this
+ /// candidate.
+ OverloadCandidateRewriteKind
+ getRewriteKind(const FunctionDecl *FD, OverloadCandidateParamOrder PO) {
+ OverloadCandidateRewriteKind CRK = CRK_None;
+ if (isRewrittenOperator(FD))
+ CRK = OverloadCandidateRewriteKind(CRK | CRK_DifferentOperator);
+ if (PO == OverloadCandidateParamOrder::Reversed)
+ CRK = OverloadCandidateRewriteKind(CRK | CRK_Reversed);
+ return CRK;
+ }
+
+ /// Determine whether we should consider looking for and adding reversed
+ /// candidates for operator Op.
+ bool shouldAddReversed(OverloadedOperatorKind Op);
+
+ /// Determine whether we should add a rewritten candidate for \p FD with
+ /// reversed parameter order.
+ bool shouldAddReversed(ASTContext &Ctx, const FunctionDecl *FD);
+ };
+
private:
SmallVector<OverloadCandidate, 16> Candidates;
- llvm::SmallPtrSet<Decl *, 16> Functions;
+ llvm::SmallPtrSet<uintptr_t, 16> Functions;
// Allocator for ConversionSequenceLists. We store the first few of these
// inline to avoid allocation for small sets.
@@ -877,11 +951,12 @@ class Sema;
SourceLocation Loc;
CandidateSetKind Kind;
+ OperatorRewriteInfo RewriteInfo;
constexpr static unsigned NumInlineBytes =
24 * sizeof(ImplicitConversionSequence);
unsigned NumInlineBytesUsed = 0;
- llvm::AlignedCharArray<alignof(void *), NumInlineBytes> InlineSpace;
+ alignas(void *) char InlineSpace[NumInlineBytes];
// Address space of the object being constructed.
LangAS DestAS = LangAS::Default;
@@ -904,7 +979,7 @@ class Sema;
unsigned NBytes = sizeof(T) * N;
if (NBytes > NumInlineBytes - NumInlineBytesUsed)
return SlabAllocator.Allocate<T>(N);
- char *FreeSpaceStart = InlineSpace.buffer + NumInlineBytesUsed;
+ char *FreeSpaceStart = InlineSpace + NumInlineBytesUsed;
assert(uintptr_t(FreeSpaceStart) % alignof(void *) == 0 &&
"Misaligned storage!");
@@ -915,19 +990,24 @@ class Sema;
void destroyCandidates();
public:
- OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK)
- : Loc(Loc), Kind(CSK) {}
+ OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK,
+ OperatorRewriteInfo RewriteInfo = {})
+ : Loc(Loc), Kind(CSK), RewriteInfo(RewriteInfo) {}
OverloadCandidateSet(const OverloadCandidateSet &) = delete;
OverloadCandidateSet &operator=(const OverloadCandidateSet &) = delete;
~OverloadCandidateSet() { destroyCandidates(); }
SourceLocation getLocation() const { return Loc; }
CandidateSetKind getKind() const { return Kind; }
+ OperatorRewriteInfo getRewriteInfo() const { return RewriteInfo; }
/// Determine when this overload candidate will be new to the
/// overload set.
- bool isNewCandidate(Decl *F) {
- return Functions.insert(F->getCanonicalDecl()).second;
+ bool isNewCandidate(Decl *F, OverloadCandidateParamOrder PO =
+ OverloadCandidateParamOrder::Normal) {
+ uintptr_t Key = reinterpret_cast<uintptr_t>(F->getCanonicalDecl());
+ Key |= static_cast<uintptr_t>(PO);
+ return Functions.insert(Key).second;
}
/// Clear out all of the candidates.
diff --git a/include/clang/Sema/ParsedAttr.h b/include/clang/Sema/ParsedAttr.h
index d87d5da04acc..d9d8585970d9 100644
--- a/include/clang/Sema/ParsedAttr.h
+++ b/include/clang/Sema/ParsedAttr.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_SEMA_ATTRIBUTELIST_H
#include "clang/Basic/AttrSubjectMatchRules.h"
+#include "clang/Basic/AttributeCommonInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/TargetInfo.h"
@@ -114,7 +115,8 @@ using ArgsVector = llvm::SmallVector<ArgsUnion, 12U>;
/// 4: __attribute__(( aligned(16) )). ParmName is unused, Args/Num used.
///
class ParsedAttr final
- : private llvm::TrailingObjects<
+ : public AttributeCommonInfo,
+ private llvm::TrailingObjects<
ParsedAttr, ArgsUnion, detail::AvailabilityData,
detail::TypeTagForDatatypeData, ParsedType, detail::PropertyData> {
friend TrailingObjects;
@@ -134,54 +136,15 @@ class ParsedAttr final
return IsProperty;
}
-public:
- /// The style used to specify an attribute.
- enum Syntax {
- /// __attribute__((...))
- AS_GNU,
-
- /// [[...]]
- AS_CXX11,
-
- /// [[...]]
- AS_C2x,
-
- /// __declspec(...)
- AS_Declspec,
-
- /// [uuid("...")] class Foo
- AS_Microsoft,
-
- /// __ptr16, alignas(...), etc.
- AS_Keyword,
-
- /// #pragma ...
- AS_Pragma,
-
- // Note TableGen depends on the order above. Do not add or change the order
- // without adding related code to TableGen/ClangAttrEmitter.cpp.
- /// Context-sensitive version of a keyword attribute.
- AS_ContextSensitiveKeyword,
- };
-
private:
- IdentifierInfo *AttrName;
- IdentifierInfo *ScopeName;
IdentifierInfo *MacroII = nullptr;
SourceLocation MacroExpansionLoc;
- SourceRange AttrRange;
- SourceLocation ScopeLoc;
SourceLocation EllipsisLoc;
- unsigned AttrKind : 16;
-
/// The number of expression arguments this attribute has.
/// The expressions themselves are stored after the object.
unsigned NumArgs : 16;
- /// Corresponds to the Syntax enum.
- unsigned SyntaxUsed : 3;
-
/// True if already diagnosed as invalid.
mutable unsigned Invalid : 1;
@@ -239,14 +202,14 @@ private:
IdentifierInfo *scopeName, SourceLocation scopeLoc,
ArgsUnion *args, unsigned numArgs, Syntax syntaxUsed,
SourceLocation ellipsisLoc)
- : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange),
- ScopeLoc(scopeLoc), EllipsisLoc(ellipsisLoc), NumArgs(numArgs),
- SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false),
- IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false),
- HasParsedType(false), HasProcessingCache(false),
- IsPragmaClangAttribute(false) {
- if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(ArgsUnion));
- AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
+ : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc,
+ syntaxUsed),
+ EllipsisLoc(ellipsisLoc), NumArgs(numArgs), Invalid(false),
+ UsedAsTypeAttr(false), IsAvailability(false),
+ IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false),
+ HasProcessingCache(false), IsPragmaClangAttribute(false) {
+ if (numArgs)
+ memcpy(getArgsBuffer(), args, numArgs * sizeof(ArgsUnion));
}
/// Constructor for availability attributes.
@@ -257,9 +220,9 @@ private:
const AvailabilityChange &obsoleted, SourceLocation unavailable,
const Expr *messageExpr, Syntax syntaxUsed, SourceLocation strict,
const Expr *replacementExpr)
- : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange),
- ScopeLoc(scopeLoc), NumArgs(1), SyntaxUsed(syntaxUsed), Invalid(false),
- UsedAsTypeAttr(false), IsAvailability(true),
+ : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc,
+ syntaxUsed),
+ NumArgs(1), Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false),
HasProcessingCache(false), IsPragmaClangAttribute(false),
UnavailableLoc(unavailable), MessageExpr(messageExpr) {
@@ -267,7 +230,6 @@ private:
memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
new (getAvailabilityData()) detail::AvailabilityData(
introduced, deprecated, obsoleted, strict, replacementExpr);
- AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
}
/// Constructor for objc_bridge_related attributes.
@@ -275,16 +237,16 @@ private:
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierLoc *Parm1, IdentifierLoc *Parm2, IdentifierLoc *Parm3,
Syntax syntaxUsed)
- : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange),
- ScopeLoc(scopeLoc), NumArgs(3), SyntaxUsed(syntaxUsed), Invalid(false),
- UsedAsTypeAttr(false), IsAvailability(false),
- IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false),
- HasProcessingCache(false), IsPragmaClangAttribute(false) {
+ : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc,
+ syntaxUsed),
+ NumArgs(3), Invalid(false), UsedAsTypeAttr(false),
+ IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false),
+ HasParsedType(false), HasProcessingCache(false),
+ IsPragmaClangAttribute(false) {
ArgsUnion *Args = getArgsBuffer();
Args[0] = Parm1;
Args[1] = Parm2;
Args[2] = Parm3;
- AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
}
/// Constructor for type_tag_for_datatype attribute.
@@ -292,31 +254,31 @@ private:
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierLoc *ArgKind, ParsedType matchingCType,
bool layoutCompatible, bool mustBeNull, Syntax syntaxUsed)
- : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange),
- ScopeLoc(scopeLoc), NumArgs(1), SyntaxUsed(syntaxUsed), Invalid(false),
- UsedAsTypeAttr(false), IsAvailability(false),
- IsTypeTagForDatatype(true), IsProperty(false), HasParsedType(false),
- HasProcessingCache(false), IsPragmaClangAttribute(false) {
+ : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc,
+ syntaxUsed),
+ NumArgs(1), Invalid(false), UsedAsTypeAttr(false),
+ IsAvailability(false), IsTypeTagForDatatype(true), IsProperty(false),
+ HasParsedType(false), HasProcessingCache(false),
+ IsPragmaClangAttribute(false) {
ArgsUnion PVal(ArgKind);
memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
detail::TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot();
new (&ExtraData.MatchingCType) ParsedType(matchingCType);
ExtraData.LayoutCompatible = layoutCompatible;
ExtraData.MustBeNull = mustBeNull;
- AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
}
/// Constructor for attributes with a single type argument.
ParsedAttr(IdentifierInfo *attrName, SourceRange attrRange,
IdentifierInfo *scopeName, SourceLocation scopeLoc,
ParsedType typeArg, Syntax syntaxUsed)
- : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange),
- ScopeLoc(scopeLoc), NumArgs(0), SyntaxUsed(syntaxUsed), Invalid(false),
- UsedAsTypeAttr(false), IsAvailability(false),
- IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(true),
- HasProcessingCache(false), IsPragmaClangAttribute(false) {
+ : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc,
+ syntaxUsed),
+ NumArgs(0), Invalid(false), UsedAsTypeAttr(false),
+ IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false),
+ HasParsedType(true), HasProcessingCache(false),
+ IsPragmaClangAttribute(false) {
new (&getTypeBuffer()) ParsedType(typeArg);
- AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
}
/// Constructor for microsoft __declspec(property) attribute.
@@ -324,13 +286,13 @@ private:
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierInfo *getterId, IdentifierInfo *setterId,
Syntax syntaxUsed)
- : AttrName(attrName), ScopeName(scopeName), AttrRange(attrRange),
- ScopeLoc(scopeLoc), NumArgs(0), SyntaxUsed(syntaxUsed), Invalid(false),
- UsedAsTypeAttr(false), IsAvailability(false),
- IsTypeTagForDatatype(false), IsProperty(true), HasParsedType(false),
- HasProcessingCache(false), IsPragmaClangAttribute(false) {
+ : AttributeCommonInfo(attrName, scopeName, attrRange, scopeLoc,
+ syntaxUsed),
+ NumArgs(0), Invalid(false), UsedAsTypeAttr(false),
+ IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(true),
+ HasParsedType(false), HasProcessingCache(false),
+ IsPragmaClangAttribute(false) {
new (&getPropertyDataBuffer()) detail::PropertyData(getterId, setterId);
- AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
}
/// Type tag information is stored immediately following the arguments, if
@@ -372,27 +334,6 @@ public:
void operator delete(void *) = delete;
- enum Kind {
- #define PARSED_ATTR(NAME) AT_##NAME,
- #include "clang/Sema/AttrParsedAttrList.inc"
- #undef PARSED_ATTR
- IgnoredAttribute,
- UnknownAttribute
- };
-
- IdentifierInfo *getName() const { return AttrName; }
- SourceLocation getLoc() const { return AttrRange.getBegin(); }
- SourceRange getRange() const { return AttrRange; }
-
- bool hasScope() const { return ScopeName; }
- IdentifierInfo *getScopeName() const { return ScopeName; }
- SourceLocation getScopeLoc() const { return ScopeLoc; }
-
- bool isGNUScope() const {
- return ScopeName &&
- (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__"));
- }
-
bool hasParsedType() const { return HasParsedType; }
/// Is this the Microsoft __declspec(property) attribute?
@@ -400,30 +341,6 @@ public:
return IsProperty;
}
- bool isAlignasAttribute() const {
- // FIXME: Use a better mechanism to determine this.
- return getKind() == AT_Aligned && isKeywordAttribute();
- }
-
- bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
- bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; }
-
- bool isCXX11Attribute() const {
- return SyntaxUsed == AS_CXX11 || isAlignasAttribute();
- }
-
- bool isC2xAttribute() const {
- return SyntaxUsed == AS_C2x;
- }
-
- bool isKeywordAttribute() const {
- return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword;
- }
-
- bool isContextSensitiveKeywordAttribute() const {
- return SyntaxUsed == AS_ContextSensitiveKeyword;
- }
-
bool isInvalid() const { return Invalid; }
void setInvalid(bool b = true) const { Invalid = b; }
@@ -450,10 +367,6 @@ public:
bool isPackExpansion() const { return EllipsisLoc.isValid(); }
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
- Kind getKind() const { return Kind(AttrKind); }
- static Kind getKind(const IdentifierInfo *Name, const IdentifierInfo *Scope,
- Syntax SyntaxUsed);
-
/// getNumArgs - Return the number of actual arguments to this attribute.
unsigned getNumArgs() const { return NumArgs; }
@@ -480,54 +393,61 @@ public:
}
const AvailabilityChange &getAvailabilityIntroduced() const {
- assert(getKind() == AT_Availability && "Not an availability attribute");
+ assert(getParsedKind() == AT_Availability &&
+ "Not an availability attribute");
return getAvailabilityData()->Changes[detail::IntroducedSlot];
}
const AvailabilityChange &getAvailabilityDeprecated() const {
- assert(getKind() == AT_Availability && "Not an availability attribute");
+ assert(getParsedKind() == AT_Availability &&
+ "Not an availability attribute");
return getAvailabilityData()->Changes[detail::DeprecatedSlot];
}
const AvailabilityChange &getAvailabilityObsoleted() const {
- assert(getKind() == AT_Availability && "Not an availability attribute");
+ assert(getParsedKind() == AT_Availability &&
+ "Not an availability attribute");
return getAvailabilityData()->Changes[detail::ObsoletedSlot];
}
SourceLocation getStrictLoc() const {
- assert(getKind() == AT_Availability && "Not an availability attribute");
+ assert(getParsedKind() == AT_Availability &&
+ "Not an availability attribute");
return getAvailabilityData()->StrictLoc;
}
SourceLocation getUnavailableLoc() const {
- assert(getKind() == AT_Availability && "Not an availability attribute");
+ assert(getParsedKind() == AT_Availability &&
+ "Not an availability attribute");
return UnavailableLoc;
}
const Expr * getMessageExpr() const {
- assert(getKind() == AT_Availability && "Not an availability attribute");
+ assert(getParsedKind() == AT_Availability &&
+ "Not an availability attribute");
return MessageExpr;
}
const Expr *getReplacementExpr() const {
- assert(getKind() == AT_Availability && "Not an availability attribute");
+ assert(getParsedKind() == AT_Availability &&
+ "Not an availability attribute");
return getAvailabilityData()->Replacement;
}
const ParsedType &getMatchingCType() const {
- assert(getKind() == AT_TypeTagForDatatype &&
+ assert(getParsedKind() == AT_TypeTagForDatatype &&
"Not a type_tag_for_datatype attribute");
return getTypeTagForDatatypeDataSlot().MatchingCType;
}
bool getLayoutCompatible() const {
- assert(getKind() == AT_TypeTagForDatatype &&
+ assert(getParsedKind() == AT_TypeTagForDatatype &&
"Not a type_tag_for_datatype attribute");
return getTypeTagForDatatypeDataSlot().LayoutCompatible;
}
bool getMustBeNull() const {
- assert(getKind() == AT_TypeTagForDatatype &&
+ assert(getParsedKind() == AT_TypeTagForDatatype &&
"Not a type_tag_for_datatype attribute");
return getTypeTagForDatatypeDataSlot().MustBeNull;
}
@@ -570,11 +490,6 @@ public:
return MacroExpansionLoc;
}
- /// Get an index into the attribute spelling list
- /// defined in Attr.td. This index is used by an attribute
- /// to pretty print itself.
- unsigned getAttributeSpellingListIndex() const;
-
bool isTargetSpecificAttr() const;
bool isTypeAttr() const;
bool isStmtAttr() const;
@@ -603,7 +518,7 @@ public:
/// If this is an OpenCL addr space attribute returns its representation
/// in LangAS, otherwise returns default addr space.
LangAS asOpenCLLangAS() const {
- switch (getKind()) {
+ switch (getParsedKind()) {
case ParsedAttr::AT_OpenCLConstantAddressSpace:
return LangAS::opencl_constant;
case ParsedAttr::AT_OpenCLGlobalAddressSpace:
@@ -618,6 +533,8 @@ public:
return LangAS::Default;
}
}
+
+ AttributeCommonInfo::Kind getKind() const { return getParsedKind(); }
};
class AttributePool;
@@ -889,8 +806,9 @@ public:
}
bool hasAttribute(ParsedAttr::Kind K) const {
- return llvm::any_of(
- AttrList, [K](const ParsedAttr *AL) { return AL->getKind() == K; });
+ return llvm::any_of(AttrList, [K](const ParsedAttr *AL) {
+ return AL->getParsedKind() == K;
+ });
}
private:
@@ -1038,28 +956,28 @@ enum AttributeDeclKind {
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const ParsedAttr &At) {
- DB.AddTaggedVal(reinterpret_cast<intptr_t>(At.getName()),
+ DB.AddTaggedVal(reinterpret_cast<intptr_t>(At.getAttrName()),
DiagnosticsEngine::ak_identifierinfo);
return DB;
}
inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
const ParsedAttr &At) {
- PD.AddTaggedVal(reinterpret_cast<intptr_t>(At.getName()),
+ PD.AddTaggedVal(reinterpret_cast<intptr_t>(At.getAttrName()),
DiagnosticsEngine::ak_identifierinfo);
return PD;
}
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
const ParsedAttr *At) {
- DB.AddTaggedVal(reinterpret_cast<intptr_t>(At->getName()),
+ DB.AddTaggedVal(reinterpret_cast<intptr_t>(At->getAttrName()),
DiagnosticsEngine::ak_identifierinfo);
return DB;
}
inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
const ParsedAttr *At) {
- PD.AddTaggedVal(reinterpret_cast<intptr_t>(At->getName()),
+ PD.AddTaggedVal(reinterpret_cast<intptr_t>(At->getAttrName()),
DiagnosticsEngine::ak_identifierinfo);
return PD;
}
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index ea2595113d58..4f7534f9ef1a 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -756,13 +756,16 @@ public:
unsigned short CapRegionKind;
unsigned short OpenMPLevel;
+ unsigned short OpenMPCaptureLevel;
CapturedRegionScopeInfo(DiagnosticsEngine &Diag, Scope *S, CapturedDecl *CD,
RecordDecl *RD, ImplicitParamDecl *Context,
- CapturedRegionKind K, unsigned OpenMPLevel)
+ CapturedRegionKind K, unsigned OpenMPLevel,
+ unsigned OpenMPCaptureLevel)
: CapturingScopeInfo(Diag, ImpCap_CapturedRegion),
TheCapturedDecl(CD), TheRecordDecl(RD), TheScope(S),
- ContextParam(Context), CapRegionKind(K), OpenMPLevel(OpenMPLevel) {
+ ContextParam(Context), CapRegionKind(K), OpenMPLevel(OpenMPLevel),
+ OpenMPCaptureLevel(OpenMPCaptureLevel) {
Kind = SK_CapturedRegion;
}
@@ -817,6 +820,9 @@ public:
/// Whether the lambda contains an unexpanded parameter pack.
bool ContainsUnexpandedParameterPack = false;
+ /// Packs introduced by this lambda, if any.
+ SmallVector<NamedDecl*, 4> LocalPacks;
+
/// If this is a generic lambda, use this as the depth of
/// each 'auto' parameter, during initial AST construction.
unsigned AutoTemplateParameterDepth = 0;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index af762f74d745..a911c61a07f8 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -57,6 +57,7 @@
#include <deque>
#include <memory>
#include <string>
+#include <tuple>
#include <vector>
namespace llvm {
@@ -158,6 +159,8 @@ namespace clang {
class OMPClause;
struct OMPVarListLocTy;
struct OverloadCandidate;
+ enum class OverloadCandidateParamOrder : char;
+ enum OverloadCandidateRewriteKind : unsigned;
class OverloadCandidateSet;
class OverloadExpr;
class ParenListExpr;
@@ -405,13 +408,20 @@ public:
/// Source location for newly created implicit MSInheritanceAttrs
SourceLocation ImplicitMSInheritanceAttrLoc;
+ /// Holds TypoExprs that are created from `createDelayedTypo`. This is used by
+ /// `TransformTypos` in order to keep track of any TypoExprs that are created
+ /// recursively during typo correction and wipe them away if the correction
+ /// fails.
+ llvm::SmallVector<TypoExpr *, 2> TypoExprs;
+
/// pragma clang section kind
enum PragmaClangSectionKind {
PCSK_Invalid = 0,
PCSK_BSS = 1,
PCSK_Data = 2,
PCSK_Rodata = 3,
- PCSK_Text = 4
+ PCSK_Text = 4,
+ PCSK_Relro = 5
};
enum PragmaClangSectionAction {
@@ -432,6 +442,7 @@ public:
PragmaClangSection PragmaClangBSSSection;
PragmaClangSection PragmaClangDataSection;
PragmaClangSection PragmaClangRodataSection;
+ PragmaClangSection PragmaClangRelroSection;
PragmaClangSection PragmaClangTextSection;
enum PragmaMsStackAction {
@@ -1039,13 +1050,6 @@ public:
/// suffice, e.g., in a default function argument.
Decl *ManglingContextDecl;
- /// The context information used to mangle lambda expressions
- /// and block literals within this context.
- ///
- /// This mangling information is allocated lazily, since most contexts
- /// do not have lambda expressions or block literals.
- std::unique_ptr<MangleNumberingContext> MangleNumbering;
-
/// If we are processing a decltype type, a set of call expressions
/// for which we have deferred checking the completeness of the return type.
SmallVector<CallExpr *, 8> DelayedDecltypeCalls;
@@ -1056,6 +1060,11 @@ public:
llvm::SmallPtrSet<const Expr *, 8> PossibleDerefs;
+ /// Expressions appearing as the LHS of a volatile assignment in this
+ /// context. We produce a warning for these when popping the context if
+ /// they are not discarded-value expressions nor unevaluated operands.
+ SmallVector<Expr*, 2> VolatileAssignmentLHSs;
+
/// \brief Describes whether we are in an expression constext which we have
/// to handle differently.
enum ExpressionKind {
@@ -1069,12 +1078,7 @@ public:
ExpressionKind ExprContext)
: Context(Context), ParentCleanup(ParentCleanup),
NumCleanupObjects(NumCleanupObjects), NumTypos(0),
- ManglingContextDecl(ManglingContextDecl), MangleNumbering(),
- ExprContext(ExprContext) {}
-
- /// Retrieve the mangling numbering context, used to consistently
- /// number constructs like lambdas for mangling.
- MangleNumberingContext &getMangleNumberingContext(ASTContext &Ctx);
+ ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext) {}
bool isUnevaluated() const {
return Context == ExpressionEvaluationContext::Unevaluated ||
@@ -1093,15 +1097,12 @@ public:
void WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec);
/// Compute the mangling number context for a lambda expression or
- /// block literal.
+ /// block literal. Also return the extra mangling decl if any.
///
/// \param DC - The DeclContext containing the lambda expression or
/// block literal.
- /// \param[out] ManglingContextDecl - Returns the ManglingContextDecl
- /// associated with the context, if relevant.
- MangleNumberingContext *getCurrentMangleNumberContext(
- const DeclContext *DC,
- Decl *&ManglingContextDecl);
+ std::tuple<MangleNumberingContext *, Decl *>
+ getCurrentMangleNumberContext(const DeclContext *DC);
/// SpecialMemberOverloadResult - The overloading result for a special member
@@ -1272,6 +1273,8 @@ public:
void addImplicitTypedef(StringRef Name, QualType T);
+ bool WarnedStackExhausted = false;
+
public:
Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind = TU_Complete,
@@ -1303,6 +1306,16 @@ public:
void PrintStats() const;
+ /// Warn that the stack is nearly exhausted.
+ void warnStackExhausted(SourceLocation Loc);
+
+ /// Run some code with "sufficient" stack space. (Currently, at least 256K is
+ /// guaranteed). Produces a warning if we're low on stack space and allocates
+ /// more in that case. Use this in code that may recurse deeply (for example,
+ /// in template instantiation) to avoid stack overflow.
+ void runWithSufficientStackSpace(SourceLocation Loc,
+ llvm::function_ref<void()> Fn);
+
/// Helper class that creates diagnostics with optional
/// template instantiation stacks.
///
@@ -1415,8 +1428,8 @@ public:
void RecordParsingTemplateParameterDepth(unsigned Depth);
void PushCapturedRegionScope(Scope *RegionScope, CapturedDecl *CD,
- RecordDecl *RD,
- CapturedRegionKind K);
+ RecordDecl *RD, CapturedRegionKind K,
+ unsigned OpenMPCaptureLevel = 0);
/// Custom deleter to allow FunctionScopeInfos to be kept alive for a short
/// time after they've been popped.
@@ -1456,6 +1469,11 @@ public:
/// Retrieve the current block, if any.
sema::BlockScopeInfo *getCurBlock();
+ /// Get the innermost lambda enclosing the current location, if any. This
+ /// looks through intervening non-lambda scopes such as local functions and
+ /// blocks.
+ sema::LambdaScopeInfo *getEnclosingLambda() const;
+
/// Retrieve the current lambda scope info, if any.
/// \param IgnoreNonLambdaCapturingScope true if should find the top-most
/// lambda scope info ignoring all inner capturing scopes that are not
@@ -1499,6 +1517,8 @@ public:
QualType BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace,
SourceLocation AttrLoc);
+ bool CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc);
+
bool CheckFunctionReturnType(QualType T, SourceLocation Loc);
/// Build a function type.
@@ -1621,7 +1641,7 @@ public:
template <std::size_t... Is>
void emit(const SemaDiagnosticBuilder &DB,
- llvm::index_sequence<Is...>) const {
+ std::index_sequence<Is...>) const {
// Apply all tuple elements to the builder in order.
bool Dummy[] = {false, (DB << getPrintable(std::get<Is>(Args)))...};
(void)Dummy;
@@ -1635,7 +1655,7 @@ public:
void diagnose(Sema &S, SourceLocation Loc, QualType T) override {
const SemaDiagnosticBuilder &DB = S.Diag(Loc, DiagID);
- emit(DB, llvm::index_sequence_for<Ts...>());
+ emit(DB, std::index_sequence_for<Ts...>());
DB << T;
}
};
@@ -1839,29 +1859,52 @@ public:
/// Describes the result of the name lookup and resolution performed
/// by \c ClassifyName().
enum NameClassificationKind {
+ /// This name is not a type or template in this context, but might be
+ /// something else.
NC_Unknown,
+ /// Classification failed; an error has been produced.
NC_Error,
+ /// The name has been typo-corrected to a keyword.
NC_Keyword,
+ /// The name was classified as a type.
NC_Type,
- NC_Expression,
- NC_NestedNameSpecifier,
+ /// The name was classified as a specific non-type, non-template
+ /// declaration. ActOnNameClassifiedAsNonType should be called to
+ /// convert the declaration to an expression.
+ NC_NonType,
+ /// The name was classified as an ADL-only function name.
+ /// ActOnNameClassifiedAsUndeclaredNonType should be called to convert the
+ /// result to an expression.
+ NC_UndeclaredNonType,
+ /// The name denotes a member of a dependent type that could not be
+ /// resolved. ActOnNameClassifiedAsDependentNonType should be called to
+ /// convert the result to an expression.
+ NC_DependentNonType,
+ /// The name was classified as a non-type, and an expression representing
+ /// that name has been formed.
+ NC_ContextIndependentExpr,
+ /// The name was classified as a template whose specializations are types.
NC_TypeTemplate,
+ /// The name was classified as a variable template name.
NC_VarTemplate,
+ /// The name was classified as a function template name.
NC_FunctionTemplate,
+ /// The name was classified as an ADL-only function template name.
NC_UndeclaredTemplate,
};
class NameClassification {
NameClassificationKind Kind;
- ExprResult Expr;
- TemplateName Template;
- ParsedType Type;
+ union {
+ ExprResult Expr;
+ NamedDecl *NonTypeDecl;
+ TemplateName Template;
+ ParsedType Type;
+ };
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) : Kind(NC_Keyword) {}
@@ -1874,8 +1917,24 @@ public:
return NameClassification(NC_Unknown);
}
- static NameClassification NestedNameSpecifier() {
- return NameClassification(NC_NestedNameSpecifier);
+ static NameClassification ContextIndependentExpr(ExprResult E) {
+ NameClassification Result(NC_ContextIndependentExpr);
+ Result.Expr = E;
+ return Result;
+ }
+
+ static NameClassification NonType(NamedDecl *D) {
+ NameClassification Result(NC_NonType);
+ Result.NonTypeDecl = D;
+ return Result;
+ }
+
+ static NameClassification UndeclaredNonType() {
+ return NameClassification(NC_UndeclaredNonType);
+ }
+
+ static NameClassification DependentNonType() {
+ return NameClassification(NC_DependentNonType);
}
static NameClassification TypeTemplate(TemplateName Name) {
@@ -1904,14 +1963,19 @@ public:
NameClassificationKind getKind() const { return Kind; }
+ ExprResult getExpression() const {
+ assert(Kind == NC_ContextIndependentExpr);
+ return Expr;
+ }
+
ParsedType getType() const {
assert(Kind == NC_Type);
return Type;
}
- ExprResult getExpression() const {
- assert(Kind == NC_Expression);
- return Expr;
+ NamedDecl *getNonTypeDecl() const {
+ assert(Kind == NC_NonType);
+ return NonTypeDecl;
}
TemplateName getTemplateName() const {
@@ -1955,17 +2019,29 @@ public:
/// \param NextToken The token following the identifier. Used to help
/// disambiguate the name.
///
- /// \param IsAddressOfOperand True if this name is the operand of a unary
- /// address of ('&') expression, assuming it is classified as an
- /// expression.
- ///
/// \param CCC The correction callback, if typo correction is desired.
NameClassification ClassifyName(Scope *S, CXXScopeSpec &SS,
IdentifierInfo *&Name, SourceLocation NameLoc,
const Token &NextToken,
- bool IsAddressOfOperand,
CorrectionCandidateCallback *CCC = nullptr);
+ /// Act on the result of classifying a name as an undeclared (ADL-only)
+ /// non-type declaration.
+ ExprResult ActOnNameClassifiedAsUndeclaredNonType(IdentifierInfo *Name,
+ SourceLocation NameLoc);
+ /// Act on the result of classifying a name as an undeclared member of a
+ /// dependent base class.
+ ExprResult ActOnNameClassifiedAsDependentNonType(const CXXScopeSpec &SS,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ bool IsAddressOfOperand);
+ /// Act on the result of classifying a name as a specific non-type
+ /// declaration.
+ ExprResult ActOnNameClassifiedAsNonType(Scope *S, const CXXScopeSpec &SS,
+ NamedDecl *Found,
+ SourceLocation NameLoc,
+ const Token &NextToken);
+
/// Describes the detailed kind of a template name. Used in diagnostics.
enum class TemplateNameKindForDiagnostics {
ClassTemplate,
@@ -2076,8 +2152,16 @@ public:
bool &AddToScope);
bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
- bool CheckConstexprFunctionDecl(const FunctionDecl *FD);
- bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body);
+ enum class CheckConstexprKind {
+ /// Diagnose issues that are non-constant or that are extensions.
+ Diagnose,
+ /// Identify whether this function satisfies the formal rules for constexpr
+ /// functions in the current lanugage mode (with no extensions).
+ CheckValid
+ };
+
+ bool CheckConstexprFunctionDefinition(const FunctionDecl *FD,
+ CheckConstexprKind Kind);
void DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD);
void FindHiddenVirtualMethods(CXXMethodDecl *MD,
@@ -2634,48 +2718,44 @@ public:
};
/// Attribute merging methods. Return true if a new attribute was added.
- AvailabilityAttr *mergeAvailabilityAttr(
- NamedDecl *D, SourceRange Range, IdentifierInfo *Platform, bool Implicit,
- VersionTuple Introduced, VersionTuple Deprecated, VersionTuple Obsoleted,
- bool IsUnavailable, StringRef Message, bool IsStrict,
- StringRef Replacement, AvailabilityMergeKind AMK, int Priority,
- unsigned AttrSpellingListIndex);
- TypeVisibilityAttr *mergeTypeVisibilityAttr(Decl *D, SourceRange Range,
- TypeVisibilityAttr::VisibilityType Vis,
- unsigned AttrSpellingListIndex);
- VisibilityAttr *mergeVisibilityAttr(Decl *D, SourceRange Range,
- VisibilityAttr::VisibilityType Vis,
- unsigned AttrSpellingListIndex);
- UuidAttr *mergeUuidAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex, StringRef Uuid);
- DLLImportAttr *mergeDLLImportAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex);
- DLLExportAttr *mergeDLLExportAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex);
+ AvailabilityAttr *
+ mergeAvailabilityAttr(NamedDecl *D, const AttributeCommonInfo &CI,
+ IdentifierInfo *Platform, bool Implicit,
+ VersionTuple Introduced, VersionTuple Deprecated,
+ VersionTuple Obsoleted, bool IsUnavailable,
+ StringRef Message, bool IsStrict, StringRef Replacement,
+ AvailabilityMergeKind AMK, int Priority);
+ TypeVisibilityAttr *
+ mergeTypeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI,
+ TypeVisibilityAttr::VisibilityType Vis);
+ VisibilityAttr *mergeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI,
+ VisibilityAttr::VisibilityType Vis);
+ UuidAttr *mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI,
+ StringRef Uuid);
+ DLLImportAttr *mergeDLLImportAttr(Decl *D, const AttributeCommonInfo &CI);
+ DLLExportAttr *mergeDLLExportAttr(Decl *D, const AttributeCommonInfo &CI);
MSInheritanceAttr *
- mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase,
- unsigned AttrSpellingListIndex,
+ mergeMSInheritanceAttr(Decl *D, const AttributeCommonInfo &CI, bool BestCase,
MSInheritanceAttr::Spelling SemanticSpelling);
- FormatAttr *mergeFormatAttr(Decl *D, SourceRange Range,
+ FormatAttr *mergeFormatAttr(Decl *D, const AttributeCommonInfo &CI,
IdentifierInfo *Format, int FormatIdx,
- int FirstArg, unsigned AttrSpellingListIndex);
- SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name,
- unsigned AttrSpellingListIndex);
- CodeSegAttr *mergeCodeSegAttr(Decl *D, SourceRange Range, StringRef Name,
- unsigned AttrSpellingListIndex);
- AlwaysInlineAttr *mergeAlwaysInlineAttr(Decl *D, SourceRange Range,
- IdentifierInfo *Ident,
- unsigned AttrSpellingListIndex);
- MinSizeAttr *mergeMinSizeAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex);
+ int FirstArg);
+ SectionAttr *mergeSectionAttr(Decl *D, const AttributeCommonInfo &CI,
+ StringRef Name);
+ CodeSegAttr *mergeCodeSegAttr(Decl *D, const AttributeCommonInfo &CI,
+ StringRef Name);
+ AlwaysInlineAttr *mergeAlwaysInlineAttr(Decl *D,
+ const AttributeCommonInfo &CI,
+ const IdentifierInfo *Ident);
+ MinSizeAttr *mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI);
NoSpeculativeLoadHardeningAttr *
mergeNoSpeculativeLoadHardeningAttr(Decl *D,
const NoSpeculativeLoadHardeningAttr &AL);
SpeculativeLoadHardeningAttr *
mergeSpeculativeLoadHardeningAttr(Decl *D,
const SpeculativeLoadHardeningAttr &AL);
- OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex);
+ OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D,
+ const AttributeCommonInfo &CI);
InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, const ParsedAttr &AL);
InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D,
const InternalLinkageAttr &AL);
@@ -2786,6 +2866,9 @@ public:
Expr *Value,
bool AllowNRVO = true);
+ bool CanPerformAggregateInitializationForOverloadResolution(
+ const InitializedEntity &Entity, InitListExpr *From);
+
bool CanPerformCopyInitialization(const InitializedEntity &Entity,
ExprResult Init);
ExprResult PerformCopyInitialization(const InitializedEntity &Entity,
@@ -2938,7 +3021,8 @@ public:
bool AllowExplicit = true,
bool AllowExplicitConversion = false,
ADLCallKind IsADLCandidate = ADLCallKind::NotADL,
- ConversionSequenceList EarlyConversions = None);
+ ConversionSequenceList EarlyConversions = None,
+ OverloadCandidateParamOrder PO = {});
void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
@@ -2951,7 +3035,8 @@ public:
Expr::Classification ObjectClassification,
ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversion = false);
+ bool SuppressUserConversion = false,
+ OverloadCandidateParamOrder PO = {});
void AddMethodCandidate(CXXMethodDecl *Method,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
@@ -2960,7 +3045,8 @@ public:
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool PartialOverloading = false,
- ConversionSequenceList EarlyConversions = None);
+ ConversionSequenceList EarlyConversions = None,
+ OverloadCandidateParamOrder PO = {});
void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
@@ -2970,23 +3056,22 @@ public:
ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
- bool PartialOverloading = false);
+ bool PartialOverloading = false,
+ OverloadCandidateParamOrder PO = {});
void AddTemplateOverloadCandidate(
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false,
bool PartialOverloading = false, bool AllowExplicit = true,
- ADLCallKind IsADLCandidate = ADLCallKind::NotADL);
- bool CheckNonDependentConversions(FunctionTemplateDecl *FunctionTemplate,
- ArrayRef<QualType> ParamTypes,
- ArrayRef<Expr *> Args,
- OverloadCandidateSet &CandidateSet,
- ConversionSequenceList &Conversions,
- bool SuppressUserConversions,
- CXXRecordDecl *ActingContext = nullptr,
- QualType ObjectType = QualType(),
- Expr::Classification
- ObjectClassification = {});
+ ADLCallKind IsADLCandidate = ADLCallKind::NotADL,
+ OverloadCandidateParamOrder PO = {});
+ bool CheckNonDependentConversions(
+ FunctionTemplateDecl *FunctionTemplate, ArrayRef<QualType> ParamTypes,
+ ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet,
+ ConversionSequenceList &Conversions, bool SuppressUserConversions,
+ CXXRecordDecl *ActingContext = nullptr, QualType ObjectType = QualType(),
+ Expr::Classification ObjectClassification = {},
+ OverloadCandidateParamOrder PO = {});
void AddConversionCandidate(
CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
@@ -3003,10 +3088,14 @@ public:
const FunctionProtoType *Proto,
Expr *Object, ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet);
+ void AddNonMemberOperatorCandidates(
+ const UnresolvedSetImpl &Functions, ArrayRef<Expr *> Args,
+ OverloadCandidateSet &CandidateSet,
+ TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr);
void AddMemberOperatorCandidates(OverloadedOperatorKind Op,
SourceLocation OpLoc, ArrayRef<Expr *> Args,
- OverloadCandidateSet& CandidateSet,
- SourceRange OpRange = SourceRange());
+ OverloadCandidateSet &CandidateSet,
+ OverloadCandidateParamOrder PO = {});
void AddBuiltinCandidate(QualType *ParamTys, ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool IsAssignmentOperator = false,
@@ -3022,9 +3111,10 @@ public:
bool PartialOverloading = false);
// Emit as a 'note' the specific overload candidate
- void NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn,
- QualType DestType = QualType(),
- bool TakingAddress = false);
+ void NoteOverloadCandidate(
+ NamedDecl *Found, FunctionDecl *Fn,
+ OverloadCandidateRewriteKind RewriteKind = OverloadCandidateRewriteKind(),
+ QualType DestType = QualType(), bool TakingAddress = false);
// Emit as a series of 'note's all template and non-templates identified by
// the expression Expr
@@ -3156,7 +3246,8 @@ public:
BinaryOperatorKind Opc,
const UnresolvedSetImpl &Fns,
Expr *LHS, Expr *RHS,
- bool RequiresADL = true);
+ bool RequiresADL = true,
+ bool AllowRewrittenCandidates = true);
ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
SourceLocation RLoc,
@@ -3384,6 +3475,7 @@ public:
LookupNameKind NameKind,
RedeclarationKind Redecl
= NotForRedeclaration);
+ bool LookupBuiltin(LookupResult &R);
bool LookupName(LookupResult &R, Scope *S,
bool AllowBuiltinCreation = false);
bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
@@ -3426,6 +3518,19 @@ public:
bool DiagnoseMissing);
bool isKnownName(StringRef name);
+ /// Status of the function emission on the CUDA/HIP/OpenMP host/device attrs.
+ enum class FunctionEmissionStatus {
+ Emitted,
+ CUDADiscarded, // Discarded due to CUDA/HIP hostness
+ OMPDiscarded, // Discarded due to OpenMP hostness
+ TemplateDiscarded, // Discarded due to uninstantiated templates
+ Unknown,
+ };
+ FunctionEmissionStatus getEmissionStatus(FunctionDecl *Decl);
+
+ // Whether the callee should be ignored in CUDA/HIP/OpenMP host/device check.
+ bool shouldIgnoreInHostDeviceCheck(FunctionDecl *Callee);
+
void ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
ArrayRef<Expr *> Args, ADLResult &Functions);
@@ -4007,7 +4112,8 @@ public:
typedef std::pair<StringRef, QualType> CapturedParamNameType;
void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
CapturedRegionKind Kind,
- ArrayRef<CapturedParamNameType> Params);
+ ArrayRef<CapturedParamNameType> Params,
+ unsigned OpenMPCaptureLevel = 0);
StmtResult ActOnCapturedRegionEnd(Stmt *S);
void ActOnCapturedRegionError();
RecordDecl *CreateCapturedStmtRecordDecl(CapturedDecl *&CD,
@@ -4215,6 +4321,9 @@ public:
ExprResult TransformToPotentiallyEvaluated(Expr *E);
ExprResult HandleExprEvaluationContextForTypeof(Expr *E);
+ ExprResult CheckUnevaluatedOperand(Expr *E);
+ void CheckUnusedVolatileAssignment(Expr *E);
+
ExprResult ActOnConstantExpression(ExprResult Res);
// Functions for marking a declaration referenced. These functions also
@@ -4349,6 +4458,10 @@ public:
TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr,
ArrayRef<Expr *> Args = None, TypoExpr **Out = nullptr);
+ DeclResult LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S,
+ IdentifierInfo *II);
+ ExprResult BuildIvarRefExpr(Scope *S, SourceLocation Loc, ObjCIvarDecl *IV);
+
ExprResult LookupInObjCMethod(LookupResult &LookUp, Scope *S,
IdentifierInfo *II,
bool AllowBuiltinCreation=false);
@@ -4606,6 +4719,12 @@ public:
MultiExprArg ArgExprs, SourceLocation RParenLoc,
Expr *ExecConfig = nullptr,
bool IsExecConfig = false);
+ enum class AtomicArgumentOrder { API, AST };
+ ExprResult
+ BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
+ SourceLocation RParenLoc, MultiExprArg Args,
+ AtomicExpr::AtomicOp Op,
+ AtomicArgumentOrder ArgOrder = AtomicArgumentOrder::API);
ExprResult
BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc,
ArrayRef<Expr *> Arg, SourceLocation RParenLoc,
@@ -4646,8 +4765,12 @@ public:
MultiExprArg InitArgList,
SourceLocation RBraceLoc);
+ ExprResult BuildInitList(SourceLocation LBraceLoc,
+ MultiExprArg InitArgList,
+ SourceLocation RBraceLoc);
+
ExprResult ActOnDesignatedInitializer(Designation &Desig,
- SourceLocation Loc,
+ SourceLocation EqualOrColonLoc,
bool GNUSyntax,
ExprResult Init);
@@ -5803,12 +5926,17 @@ public:
LambdaCaptureDefault CaptureDefault);
/// Start the definition of a lambda expression.
- CXXMethodDecl *
- startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange,
- TypeSourceInfo *MethodType, SourceLocation EndLoc,
- ArrayRef<ParmVarDecl *> Params,
- ConstexprSpecKind ConstexprKind,
- Optional<std::pair<unsigned, Decl *>> Mangling = None);
+ CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class,
+ SourceRange IntroducerRange,
+ TypeSourceInfo *MethodType,
+ SourceLocation EndLoc,
+ ArrayRef<ParmVarDecl *> Params,
+ ConstexprSpecKind ConstexprKind);
+
+ /// Number lambda for linkage purposes if necessary.
+ void handleLambdaNumbering(
+ CXXRecordDecl *Class, CXXMethodDecl *Method,
+ Optional<std::tuple<unsigned, bool, Decl *>> Mangling = None);
/// Endow the lambda scope info with the relevant properties.
void buildLambdaScope(sema::LambdaScopeInfo *LSI,
@@ -5936,6 +6064,21 @@ public:
CXXConversionDecl *Conv,
Expr *Src);
+ /// Check whether the given expression is a valid constraint expression.
+ /// A diagnostic is emitted if it is not, and false is returned.
+ bool CheckConstraintExpression(Expr *CE);
+
+ bool CalculateConstraintSatisfaction(ConceptDecl *NamedConcept,
+ MultiLevelTemplateArgumentList &MLTAL,
+ Expr *ConstraintExpr,
+ bool &IsSatisfied);
+
+ /// Check that the associated constraints of a template declaration match the
+ /// associated constraints of an older declaration of which it is a
+ /// redeclaration.
+ bool CheckRedeclarationConstraintMatch(TemplateParameterList *Old,
+ TemplateParameterList *New);
+
// ParseObjCStringLiteral - Parse Objective-C string literals.
ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
ArrayRef<Expr *> Strings);
@@ -6150,6 +6293,17 @@ public:
ClassTemplateSpecializationDecl *BaseTemplateSpec,
SourceLocation BaseLoc);
+ /// Add gsl::Pointer attribute to std::container::iterator
+ /// \param ND The declaration that introduces the name
+ /// std::container::iterator. \param UnderlyingRecord The record named by ND.
+ void inferGslPointerAttribute(NamedDecl *ND, CXXRecordDecl *UnderlyingRecord);
+
+ /// Add [[gsl::Owner]] and [[gsl::Pointer]] attributes for std:: types.
+ void inferGslOwnerPointerAttribute(CXXRecordDecl *Record);
+
+ /// Add [[gsl::Pointer]] attributes for std:: types.
+ void inferGslPointerAttribute(TypedefNameDecl *TD);
+
void CheckCompletedCXXClass(CXXRecordDecl *Record);
/// Check that the C++ class annoated with "trivial_abi" satisfies all the
@@ -6596,9 +6750,9 @@ public:
ExprResult
CheckConceptTemplateId(const CXXScopeSpec &SS,
- const DeclarationNameInfo &NameInfo,
- ConceptDecl *Template,
- SourceLocation TemplateLoc,
+ SourceLocation TemplateKWLoc,
+ SourceLocation ConceptNameLoc, NamedDecl *FoundDecl,
+ ConceptDecl *NamedConcept,
const TemplateArgumentListInfo *TemplateArgs);
void diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc);
@@ -7517,6 +7671,18 @@ public:
/// member).
DefiningSynthesizedFunction,
+ // We are checking the constraints associated with a constrained entity or
+ // the constraint expression of a concept. This includes the checks that
+ // atomic constraints have the type 'bool' and that they can be constant
+ // evaluated.
+ ConstraintsCheck,
+
+ // We are substituting template arguments into a constraint expression.
+ ConstraintSubstitution,
+
+ /// We are rewriting a comparison operator in terms of an operator<=>.
+ RewritingOperatorAsSpaceship,
+
/// Added for Template instantiation observation.
/// Memoization means we are _not_ instantiating a template because
/// it is already instantiated (but we entered a context where we
@@ -7777,6 +7943,23 @@ public:
ArrayRef<TemplateArgument> TemplateArgs,
SourceRange InstantiationRange);
+ struct ConstraintsCheck {};
+ /// \brief Note that we are checking the constraints associated with some
+ /// constrained entity (a concept declaration or a template with associated
+ /// constraints).
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ConstraintsCheck, TemplateDecl *Template,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange InstantiationRange);
+
+ struct ConstraintSubstitution {};
+ /// \brief Note that we are checking a constraint expression associated
+ /// with a template declaration or as part of the satisfaction check of a
+ /// concept.
+ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ConstraintSubstitution, TemplateDecl *Template,
+ sema::TemplateDeductionInfo &DeductionInfo,
+ SourceRange InstantiationRange);
/// Note that we have finished instantiating this template.
void Clear();
@@ -8225,6 +8408,11 @@ public:
LocalInstantiationScope *StartingScope,
bool InstantiatingVarTemplate = false,
VarTemplateSpecializationDecl *PrevVTSD = nullptr);
+
+ VarDecl *getVarTemplateSpecialization(
+ VarTemplateDecl *VarTempl, const TemplateArgumentListInfo *TemplateArgs,
+ const DeclarationNameInfo &MemberNameInfo, SourceLocation TemplateKWLoc);
+
void InstantiateVariableInitializer(
VarDecl *Var, VarDecl *OldVar,
const MultiLevelTemplateArgumentList &TemplateArgs);
@@ -8844,51 +9032,50 @@ public:
void AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD, SourceLocation Loc);
/// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
- void AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
- unsigned SpellingListIndex, bool IsPackExpansion);
- void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T,
- unsigned SpellingListIndex, bool IsPackExpansion);
+ void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
+ bool IsPackExpansion);
+ void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, TypeSourceInfo *T,
+ bool IsPackExpansion);
/// AddAssumeAlignedAttr - Adds an assume_aligned attribute to a particular
/// declaration.
- void AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, Expr *OE,
- unsigned SpellingListIndex);
+ void AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
+ Expr *OE);
/// AddAllocAlignAttr - Adds an alloc_align attribute to a particular
/// declaration.
- void AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr,
- unsigned SpellingListIndex);
+ void AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI,
+ Expr *ParamExpr);
/// AddAlignValueAttr - Adds an align_value attribute to a particular
/// declaration.
- void AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
- unsigned SpellingListIndex);
+ void AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E);
/// AddLaunchBoundsAttr - Adds a launch_bounds attribute to a particular
/// declaration.
- void AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads,
- Expr *MinBlocks, unsigned SpellingListIndex);
+ void AddLaunchBoundsAttr(Decl *D, const AttributeCommonInfo &CI,
+ Expr *MaxThreads, Expr *MinBlocks);
/// AddModeAttr - Adds a mode attribute to a particular declaration.
- void AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name,
- unsigned SpellingListIndex, bool InInstantiation = false);
+ void AddModeAttr(Decl *D, const AttributeCommonInfo &CI, IdentifierInfo *Name,
+ bool InInstantiation = false);
- void AddParameterABIAttr(SourceRange AttrRange, Decl *D,
- ParameterABI ABI, unsigned SpellingListIndex);
+ void AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI,
+ ParameterABI ABI);
enum class RetainOwnershipKind {NS, CF, OS};
- void AddXConsumedAttr(Decl *D, SourceRange SR, unsigned SpellingIndex,
+ void AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI,
RetainOwnershipKind K, bool IsTemplateInstantiation);
/// addAMDGPUFlatWorkGroupSizeAttr - Adds an amdgpu_flat_work_group_size
/// attribute to a particular declaration.
- void addAMDGPUFlatWorkGroupSizeAttr(SourceRange AttrRange, Decl *D, Expr *Min,
- Expr *Max, unsigned SpellingListIndex);
+ void addAMDGPUFlatWorkGroupSizeAttr(Decl *D, const AttributeCommonInfo &CI,
+ Expr *Min, Expr *Max);
/// addAMDGPUWavePersEUAttr - Adds an amdgpu_waves_per_eu attribute to a
/// particular declaration.
- void addAMDGPUWavesPerEUAttr(SourceRange AttrRange, Decl *D, Expr *Min,
- Expr *Max, unsigned SpellingListIndex);
+ void addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI,
+ Expr *Min, Expr *Max);
bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type);
@@ -9002,6 +9189,10 @@ private:
void adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex,
unsigned Level) const;
+ /// Returns the number of scopes associated with the construct on the given
+ /// OpenMP level.
+ int getNumberOfConstructScopes(unsigned Level) const;
+
/// Push new OpenMP function region for non-capturing function.
void pushOpenMPFunctionRegion();
@@ -9009,12 +9200,21 @@ private:
void popOpenMPFunctionRegion(const sema::FunctionScopeInfo *OldFSI);
/// Check whether we're allowed to call Callee from the current function.
- void checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee);
+ void checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee,
+ bool CheckForDelayedContext = true);
+
+ /// Check whether we're allowed to call Callee from the current function.
+ void checkOpenMPHostFunction(SourceLocation Loc, FunctionDecl *Callee,
+ bool CheckCaller = true);
/// Check if the expression is allowed to be used in expressions for the
/// OpenMP devices.
void checkOpenMPDeviceExpr(const Expr *E);
+ /// Finishes analysis of the deferred functions calls that may be declared as
+ /// host/nohost during device/host compilation.
+ void finalizeOpenMPDelayedAnalysis();
+
/// Checks if a type or a declaration is disabled due to the owning extension
/// being disabled, and emits diagnostic messages if it is disabled.
/// \param D type or declaration to be checked.
@@ -9030,7 +9230,39 @@ private:
MapT &Map, unsigned Selector = 0,
SourceRange SrcRange = SourceRange());
+ /// Marks all the functions that might be required for the currently active
+ /// OpenMP context.
+ void markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc,
+ FunctionDecl *Func,
+ bool MightBeOdrUse);
+
public:
+ /// Struct to store the context selectors info for declare variant directive.
+ struct OpenMPDeclareVariantCtsSelectorData {
+ OMPDeclareVariantAttr::CtxSelectorSetType CtxSet =
+ OMPDeclareVariantAttr::CtxSetUnknown;
+ OMPDeclareVariantAttr::CtxSelectorType Ctx =
+ OMPDeclareVariantAttr::CtxUnknown;
+ MutableArrayRef<StringRef> ImplVendors;
+ ExprResult CtxScore;
+ explicit OpenMPDeclareVariantCtsSelectorData() = default;
+ explicit OpenMPDeclareVariantCtsSelectorData(
+ OMPDeclareVariantAttr::CtxSelectorSetType CtxSet,
+ OMPDeclareVariantAttr::CtxSelectorType Ctx,
+ MutableArrayRef<StringRef> ImplVendors, ExprResult CtxScore)
+ : CtxSet(CtxSet), Ctx(Ctx), ImplVendors(ImplVendors),
+ CtxScore(CtxScore) {}
+ };
+
+ /// Checks if the variant/multiversion functions are compatible.
+ bool areMultiversionVariantFunctionsCompatible(
+ const FunctionDecl *OldFD, const FunctionDecl *NewFD,
+ const PartialDiagnostic &NoProtoDiagID,
+ const PartialDiagnosticAt &NoteCausedDiagIDAt,
+ const PartialDiagnosticAt &NoSupportDiagIDAt,
+ const PartialDiagnosticAt &DiffDiagIDAt, bool TemplatesSupported,
+ bool ConstexprSupported, bool CLinkageMayDiffer);
+
/// Function tries to capture lambda's captured variables in the OpenMP region
/// before the original lambda is captured.
void tryCaptureOpenMPLambdas(ValueDecl *V);
@@ -9039,7 +9271,9 @@ public:
/// reference.
/// \param Level Relative level of nested OpenMP construct for that the check
/// is performed.
- bool isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const;
+ /// \param OpenMPCaptureLevel Capture level within an OpenMP construct.
+ bool isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
+ unsigned OpenMPCaptureLevel) const;
/// Check if the specified variable is used in one of the private
/// clauses (private, firstprivate, lastprivate, reduction etc.) in OpenMP
@@ -9053,6 +9287,10 @@ public:
/// construct.
void startOpenMPLoop();
+ /// If the current region is a range loop-based region, mark the start of the
+ /// loop construct.
+ void startOpenMPCXXRangeFor();
+
/// Check if the specified variable is used in 'private' clause.
/// \param Level Relative level of nested OpenMP construct for that the check
/// is performed.
@@ -9159,11 +9397,16 @@ public:
bool ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc);
/// Called at the end of target region i.e. '#pragme omp end declare target'.
void ActOnFinishOpenMPDeclareTargetDirective();
+ /// Searches for the provided declaration name for OpenMP declare target
+ /// directive.
+ NamedDecl *
+ lookupOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec,
+ const DeclarationNameInfo &Id,
+ NamedDeclSetType &SameDirectiveDecls);
/// Called on correct id-expression from the '#pragma omp declare target'.
- void ActOnOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec,
- const DeclarationNameInfo &Id,
+ void ActOnOpenMPDeclareTargetName(NamedDecl *ND, SourceLocation Loc,
OMPDeclareTargetDeclAttr::MapTypeTy MT,
- NamedDeclSetType &SameDirectiveDecls);
+ OMPDeclareTargetDeclAttr::DevTypeTy DT);
/// Check declaration inside target region.
void
checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
@@ -9348,6 +9591,21 @@ public:
StmtResult ActOnOpenMPTaskLoopSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA);
+ /// Called on well-formed '\#pragma omp master taskloop' after parsing of the
+ /// associated statement.
+ StmtResult ActOnOpenMPMasterTaskLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA);
+ /// Called on well-formed '\#pragma omp master taskloop simd' after parsing of
+ /// the associated statement.
+ StmtResult ActOnOpenMPMasterTaskLoopSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA);
+ /// Called on well-formed '\#pragma omp parallel master taskloop' after
+ /// parsing of the associated statement.
+ StmtResult ActOnOpenMPParallelMasterTaskLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA);
/// Called on well-formed '\#pragma omp distribute' after parsing
/// of the associated statement.
StmtResult
@@ -9448,6 +9706,29 @@ public:
ArrayRef<Expr *> Alignments, ArrayRef<Expr *> Linears,
ArrayRef<unsigned> LinModifiers, ArrayRef<Expr *> Steps, SourceRange SR);
+ /// Checks '\#pragma omp declare variant' variant function and original
+ /// functions after parsing of the associated method/function.
+ /// \param DG Function declaration to which declare variant directive is
+ /// applied to.
+ /// \param VariantRef Expression that references the variant function, which
+ /// must be used instead of the original one, specified in \p DG.
+ /// \returns None, if the function/variant function are not compatible with
+ /// the pragma, pair of original function/variant ref expression otherwise.
+ Optional<std::pair<FunctionDecl *, Expr *>> checkOpenMPDeclareVariantFunction(
+ DeclGroupPtrTy DG, Expr *VariantRef, SourceRange SR);
+
+ /// Called on well-formed '\#pragma omp declare variant' after parsing of
+ /// the associated method/function.
+ /// \param FD Function declaration to which declare variant directive is
+ /// applied to.
+ /// \param VariantRef Expression that references the variant function, which
+ /// must be used instead of the original one, specified in \p DG.
+ /// \param Data Set of context-specific data for the specified context
+ /// selector.
+ void ActOnOpenMPDeclareVariantDirective(
+ FunctionDecl *FD, Expr *VariantRef, SourceRange SR,
+ const Sema::OpenMPDeclareVariantCtsSelectorData &Data);
+
OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
Expr *Expr,
SourceLocation StartLoc,
@@ -10051,6 +10332,7 @@ public:
QualType CheckShiftOperands( // C99 6.5.7
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
BinaryOperatorKind Opc, bool IsCompAssign = false);
+ void CheckPtrComparisonWithNullChar(ExprResult &E, ExprResult &NullE);
QualType CheckCompareOperands( // C99 6.5.8/9
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc,
BinaryOperatorKind Opc);
@@ -10137,11 +10419,11 @@ public:
Ref_Compatible
};
- ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc,
- QualType T1, QualType T2,
- bool &DerivedToBase,
- bool &ObjCConversion,
- bool &ObjCLifetimeConversion);
+ ReferenceCompareResult
+ CompareReferenceRelationship(SourceLocation Loc, QualType T1, QualType T2,
+ bool &DerivedToBase, bool &ObjCConversion,
+ bool &ObjCLifetimeConversion,
+ bool &FunctionConversion);
ExprResult checkUnknownAnyCast(SourceRange TypeRange, QualType CastType,
Expr *CastExpr, CastKind &CastKind,
@@ -10546,6 +10828,21 @@ public:
/// // Otherwise, continue parsing as normal.
DeviceDiagBuilder diagIfOpenMPDeviceCode(SourceLocation Loc, unsigned DiagID);
+ /// Creates a DeviceDiagBuilder that emits the diagnostic if the current
+ /// context is "used as host code".
+ ///
+ /// - If CurContext is a `declare target` function or it is known that the
+ /// function is emitted for the host, emits the diagnostics immediately.
+ /// - If CurContext is a non-host function, just ignore it.
+ ///
+ /// Example usage:
+ ///
+ /// // Variable-length arrays are not allowed in NVPTX device code.
+ /// if (diagIfOpenMPHostode(Loc, diag::err_vla_unsupported))
+ /// return ExprError();
+ /// // Otherwise, continue parsing as normal.
+ DeviceDiagBuilder diagIfOpenMPHostCode(SourceLocation Loc, unsigned DiagID);
+
DeviceDiagBuilder targetDiag(SourceLocation Loc, unsigned DiagID);
enum CUDAFunctionTarget {
@@ -10907,6 +11204,7 @@ private:
bool CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
+ bool CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall);
bool CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall);
@@ -11165,6 +11463,7 @@ public:
// Emitting members of dllexported classes is delayed until the class
// (including field initializers) is fully parsed.
SmallVector<CXXRecordDecl*, 4> DelayedDllExportClasses;
+ SmallVector<CXXMethodDecl*, 4> DelayedDllExportMemberFunctions;
private:
class SavePendingParsedClassStateRAII {
diff --git a/include/clang/Sema/SemaInternal.h b/include/clang/Sema/SemaInternal.h
index dfb34daa14d3..cdaf7b70a92f 100644
--- a/include/clang/Sema/SemaInternal.h
+++ b/include/clang/Sema/SemaInternal.h
@@ -97,7 +97,7 @@ public:
bool EnteringContext)
: Typo(TypoName.getName().getAsIdentifierInfo()), CurrentTCIndex(0),
SavedTCIndex(0), SemaRef(SemaRef), S(S),
- SS(SS ? llvm::make_unique<CXXScopeSpec>(*SS) : nullptr),
+ SS(SS ? std::make_unique<CXXScopeSpec>(*SS) : nullptr),
CorrectionValidator(std::move(CCC)), MemberContext(MemberContext),
Result(SemaRef, TypoName, LookupKind),
Namespaces(SemaRef.Context, SemaRef.CurContext, SS),
diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h
index b49a96c0b93f..e0f8d152dbe5 100644
--- a/include/clang/Sema/TypoCorrection.h
+++ b/include/clang/Sema/TypoCorrection.h
@@ -356,7 +356,7 @@ public:
: CorrectionCandidateCallback(Typo, TypoNNS) {}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<DefaultFilterCCC>(*this);
+ return std::make_unique<DefaultFilterCCC>(*this);
}
};
@@ -369,7 +369,7 @@ public:
return candidate.getCorrectionDeclAs<C>();
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<DeclFilterCCC>(*this);
+ return std::make_unique<DeclFilterCCC>(*this);
}
};
@@ -384,7 +384,7 @@ public:
bool ValidateCandidate(const TypoCorrection &candidate) override;
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<FunctionCallFilterCCC>(*this);
+ return std::make_unique<FunctionCallFilterCCC>(*this);
}
private:
@@ -409,7 +409,7 @@ public:
return false;
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<NoTypoCorrectionCCC>(*this);
+ return std::make_unique<NoTypoCorrectionCCC>(*this);
}
};
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 0e1b9e0af9e6..f31057275479 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -41,7 +41,7 @@ namespace serialization {
/// Version 4 of AST files also requires that the version control branch and
/// revision match exactly, since there is no backward compatibility of
/// AST files at this time.
- const unsigned VERSION_MAJOR = 7;
+ const unsigned VERSION_MAJOR = 8;
/// AST file minor version number supported by this version of
/// Clang.
@@ -382,7 +382,10 @@ namespace serialization {
/// inside the control block.
enum InputFileRecordTypes {
/// An input file.
- INPUT_FILE = 1
+ INPUT_FILE = 1,
+
+ /// The input file content hash
+ INPUT_FILE_HASH
};
/// Record types that occur within the AST block itself.
@@ -1018,6 +1021,9 @@ namespace serialization {
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
PREDEF_TYPE_##Id##_ID,
#include "clang/Basic/OpenCLExtensionTypes.def"
+ // \brief SVE types with auto numeration
+#define SVE_TYPE(Name, Id, SingletonId) PREDEF_TYPE_##Id##_ID,
+#include "clang/Basic/AArch64SVEACLETypes.def"
};
/// The number of predefined type IDs that are reserved for
@@ -1839,6 +1845,9 @@ namespace serialization {
/// A CXXMemberCallExpr record.
EXPR_CXX_MEMBER_CALL,
+ /// A CXXRewrittenBinaryOperator record.
+ EXPR_CXX_REWRITTEN_BINARY_OPERATOR,
+
/// A CXXConstructExpr record.
EXPR_CXX_CONSTRUCT,
@@ -1909,6 +1918,7 @@ namespace serialization {
EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr
EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr
EXPR_CXX_FOLD, // CXXFoldExpr
+ EXPR_CONCEPT_SPECIALIZATION,// ConceptSpecializationExpr
// CUDA
EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr
@@ -1958,6 +1968,9 @@ namespace serialization {
STMT_OMP_CANCEL_DIRECTIVE,
STMT_OMP_TASKLOOP_DIRECTIVE,
STMT_OMP_TASKLOOP_SIMD_DIRECTIVE,
+ STMT_OMP_MASTER_TASKLOOP_DIRECTIVE,
+ STMT_OMP_MASTER_TASKLOOP_SIMD_DIRECTIVE,
+ STMT_OMP_PARALLEL_MASTER_TASKLOOP_DIRECTIVE,
STMT_OMP_DISTRIBUTE_DIRECTIVE,
STMT_OMP_TARGET_UPDATE_DIRECTIVE,
STMT_OMP_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE,
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 37bea48d8846..7495c2b17aa2 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -930,6 +930,9 @@ private:
/// Whether validate system input files.
bool ValidateSystemInputs;
+ /// Whether validate headers and module maps using hash based on contents.
+ bool ValidateASTInputFilesContent;
+
/// Whether we are allowed to use the global module index.
bool UseGlobalIndex;
@@ -1203,6 +1206,7 @@ private:
struct InputFileInfo {
std::string Filename;
+ uint64_t ContentHash;
off_t StoredSize;
time_t StoredTime;
bool Overridden;
@@ -1437,6 +1441,8 @@ private:
void Error(StringRef Msg) const;
void Error(unsigned DiagID, StringRef Arg1 = StringRef(),
StringRef Arg2 = StringRef()) const;
+ void Error(unsigned DiagID, StringRef Arg1, StringRef Arg2,
+ unsigned Select) const;
void Error(llvm::Error &&Err) const;
public:
@@ -1485,7 +1491,9 @@ public:
StringRef isysroot = "", bool DisableValidation = false,
bool AllowASTWithCompilerErrors = false,
bool AllowConfigurationMismatch = false,
- bool ValidateSystemInputs = false, bool UseGlobalIndex = true,
+ bool ValidateSystemInputs = false,
+ bool ValidateASTInputFilesContent = false,
+ bool UseGlobalIndex = true,
std::unique_ptr<llvm::Timer> ReadTimer = {});
ASTReader(const ASTReader &) = delete;
ASTReader &operator=(const ASTReader &) = delete;
@@ -1578,7 +1586,7 @@ public:
/// Takes ownership of \p L.
void addListener(std::unique_ptr<ASTReaderListener> L) {
if (Listener)
- L = llvm::make_unique<ChainedASTReaderListener>(std::move(L),
+ L = std::make_unique<ChainedASTReaderListener>(std::move(L),
std::move(Listener));
Listener = std::move(L);
}
@@ -1594,7 +1602,7 @@ public:
auto Old = Reader.takeListener();
if (Old) {
Chained = true;
- L = llvm::make_unique<ChainedASTReaderListener>(std::move(L),
+ L = std::make_unique<ChainedASTReaderListener>(std::move(L),
std::move(Old));
}
Reader.setListener(std::move(L));
diff --git a/include/clang/StaticAnalyzer/Checkers/Checkers.td b/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 2b29efba66a4..4d52655045b3 100644
--- a/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -504,6 +504,15 @@ def MoveChecker: Checker<"Move">,
]>,
Documentation<HasDocumentation>;
+def VirtualCallModeling : Checker<"VirtualCallModeling">,
+ HelpText<"Auxiliary modeling for the virtual method call checkers">,
+ Documentation<NotDocumented>,
+ Hidden;
+
+def PureVirtualCallChecker : Checker<"PureVirtualCall">,
+ HelpText<"Check pure virtual function calls during construction/destruction">,
+ Dependencies<[VirtualCallModeling]>,
+ Documentation<HasDocumentation>;
} // end: "cplusplus"
let ParentPackage = CplusplusOptIn in {
@@ -552,14 +561,22 @@ def UninitializedObjectChecker: Checker<"UninitializedObject">,
Documentation<HasAlphaDocumentation>;
def VirtualCallChecker : Checker<"VirtualCall">,
- HelpText<"Check virtual function calls during construction or destruction">,
+ HelpText<"Check virtual function calls during construction/destruction">,
CheckerOptions<[
CmdLineOption<Boolean,
+ "ShowFixIts",
+ "Enable fix-it hints for this checker",
+ "false",
+ InAlpha>,
+ CmdLineOption<Boolean,
"PureOnly",
- "Whether to only report calls to pure virtual methods.",
+ "Disables the checker. Keeps cplusplus.PureVirtualCall "
+ "enabled. This option is only provided for backwards "
+ "compatibility.",
"false",
- Released>
+ InAlpha>
]>,
+ Dependencies<[VirtualCallModeling]>,
Documentation<HasDocumentation>;
} // end: "optin.cplusplus"
@@ -636,6 +653,19 @@ let ParentPackage = DeadCode in {
def DeadStoresChecker : Checker<"DeadStores">,
HelpText<"Check for values stored to variables that are never read "
"afterwards">,
+ CheckerOptions<[
+ CmdLineOption<Boolean,
+ "WarnForDeadNestedAssignments",
+ "Warns for deadstores in nested assignments."
+ "E.g.: if ((P = f())) where P is unused.",
+ "true",
+ Released>,
+ CmdLineOption<Boolean,
+ "ShowFixIts",
+ "Enable fix-it hints for this checker",
+ "false",
+ InAlpha>
+ ]>,
Documentation<HasDocumentation>;
} // end DeadCode
@@ -799,6 +829,13 @@ let ParentPackage = Taint in {
def GenericTaintChecker : Checker<"TaintPropagation">,
HelpText<"Generate taint information used by other checkers">,
+ CheckerOptions<[
+ CmdLineOption<String,
+ "Config",
+ "Specifies the name of the configuration file.",
+ "",
+ InAlpha>,
+ ]>,
Documentation<HasAlphaDocumentation>;
} // end "alpha.security.taint"
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
index 70bd476b6c43..d853fb74f9c7 100644
--- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
@@ -294,12 +294,20 @@ ANALYZER_OPTION(bool, DisplayCTUProgress, "display-ctu-progress",
ANALYZER_OPTION(bool, ShouldTrackConditions, "track-conditions",
"Whether to track conditions that are a control dependency of "
"an already tracked variable.",
- false)
+ true)
ANALYZER_OPTION(bool, ShouldTrackConditionsDebug, "track-conditions-debug",
"Whether to place an event at each tracked condition.",
false)
+ANALYZER_OPTION(bool, ShouldEmitFixItHintsAsRemarks, "fixits-as-remarks",
+ "Emit fix-it hints as remarks for testing purposes",
+ false)
+
+//===----------------------------------------------------------------------===//
+// Unsigned analyzer options.
+//===----------------------------------------------------------------------===//
+
ANALYZER_OPTION(unsigned, CTUImportThreshold, "ctu-import-threshold",
"The maximal amount of translation units that is considered "
"for import when inlining functions during CTU analysis. "
@@ -308,10 +316,6 @@ ANALYZER_OPTION(unsigned, CTUImportThreshold, "ctu-import-threshold",
"various translation units.",
100u)
-//===----------------------------------------------------------------------===//
-// Unsinged analyzer options.
-//===----------------------------------------------------------------------===//
-
ANALYZER_OPTION(
unsigned, AlwaysInlineSize, "ipa-always-inline-size",
"The size of the functions (in basic blocks), which should be considered "
@@ -380,12 +384,6 @@ ANALYZER_OPTION(
"Value: \"constructors\", \"destructors\", \"methods\".",
"destructors")
-ANALYZER_OPTION_DEPENDS_ON_USER_MODE(
- StringRef, IPAMode, "ipa",
- "Controls the mode of inter-procedural analysis. Value: \"none\", "
- "\"basic-inlining\", \"inlining\", \"dynamic\", \"dynamic-bifurcate\".",
- /* SHALLOW_VAL */ "inlining", /* DEEP_VAL */ "dynamic-bifurcate")
-
ANALYZER_OPTION(
StringRef, ExplorationStrategy, "exploration_strategy",
"Value: \"dfs\", \"bfs\", \"unexplored_first\", "
@@ -393,5 +391,17 @@ ANALYZER_OPTION(
"\"bfs_block_dfs_contents\".",
"unexplored_first_queue")
+ANALYZER_OPTION(
+ StringRef, RawSilencedCheckersAndPackages, "silence-checkers",
+ "A semicolon separated list of checker and package names to silence. "
+ "Silenced checkers will not emit reports, but the modeling remain enabled.",
+ "")
+
+ANALYZER_OPTION_DEPENDS_ON_USER_MODE(
+ StringRef, IPAMode, "ipa",
+ "Controls the mode of inter-procedural analysis. Value: \"none\", "
+ "\"basic-inlining\", \"inlining\", \"dynamic\", \"dynamic-bifurcate\".",
+ /* SHALLOW_VAL */ "inlining", /* DEEP_VAL */ "dynamic-bifurcate")
+
#undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE
#undef ANALYZER_OPTION
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index 9630a229bd3b..ce16095e10c0 100644
--- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -163,9 +163,16 @@ class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
public:
using ConfigTable = llvm::StringMap<std::string>;
+ /// Retrieves the list of checkers generated from Checkers.td. This doesn't
+ /// contain statically linked but non-generated checkers and plugin checkers!
static std::vector<StringRef>
getRegisteredCheckers(bool IncludeExperimental = false);
+ /// Retrieves the list of packages generated from Checkers.td. This doesn't
+ /// contain statically linked but non-generated packages and plugin packages!
+ static std::vector<StringRef>
+ getRegisteredPackages(bool IncludeExperimental = false);
+
/// Convenience function for printing options or checkers and their
/// description in a formatted manner. If \p MinLineWidth is set to 0, no line
/// breaks are introduced for the description.
@@ -188,9 +195,11 @@ public:
std::pair<StringRef, StringRef> EntryDescPair,
size_t EntryWidth, size_t InitialPad, size_t MinLineWidth = 0);
+ /// Pairs of checker/package name and enable/disable.
+ std::vector<std::pair<std::string, bool>> CheckersAndPackages;
- /// Pair of checker name and enable/disable.
- std::vector<std::pair<std::string, bool>> CheckersControlList;
+ /// Vector of checker/package names which will not emit warnings.
+ std::vector<std::string> SilencedCheckersAndPackages;
/// A key-value table of use-specified configuration values.
// TODO: This shouldn't be public.
@@ -212,12 +221,12 @@ public:
/// The maximum number of times the analyzer visits a block.
unsigned maxBlockVisitOnPath;
- /// Disable all analyzer checks.
+ /// Disable all analyzer checkers.
///
- /// This flag allows one to disable analyzer checks on the code processed by
+ /// This flag allows one to disable analyzer checkers on the code processed by
/// the given analysis consumer. Note, the code will get parsed and the
/// command-line options will get checked.
- unsigned DisableAllChecks : 1;
+ unsigned DisableAllCheckers : 1;
unsigned ShowCheckerHelp : 1;
unsigned ShowCheckerHelpAlpha : 1;
@@ -269,13 +278,13 @@ public:
// Create an array of all -analyzer-config command line options. Sort it in
// the constructor.
- std::vector<StringRef> AnalyzerConfigCmdFlags = {
+ std::vector<llvm::StringLiteral> AnalyzerConfigCmdFlags = {
#define ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC, \
SHALLOW_VAL, DEEP_VAL) \
ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL)
#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL) \
- CMDFLAG,
+ llvm::StringLiteral(CMDFLAG),
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def"
#undef ANALYZER_OPTION
@@ -292,7 +301,7 @@ public:
}
AnalyzerOptions()
- : DisableAllChecks(false), ShowCheckerHelp(false),
+ : DisableAllCheckers(false), ShowCheckerHelp(false),
ShowCheckerHelpAlpha(false), ShowCheckerHelpDeveloper(false),
ShowCheckerOptionList(false), ShowCheckerOptionAlphaList(false),
ShowCheckerOptionDeveloperList(false), ShowEnabledCheckerList(false),
@@ -310,7 +319,7 @@ public:
/// If an option value is not provided, returns the given \p DefaultVal.
/// @param [in] CheckerName The *full name* of the checker. One may retrieve
/// this from the checker object's field \c Name, or through \c
- /// CheckerManager::getCurrentCheckName within the checker's registry
+ /// CheckerManager::getCurrentCheckerName within the checker's registry
/// function.
/// Checker options are retrieved in the following format:
/// `-analyzer-config CheckerName:OptionName=Value.
@@ -330,7 +339,7 @@ public:
/// If an option value is not provided, returns the given \p DefaultVal.
/// @param [in] CheckerName The *full name* of the checker. One may retrieve
/// this from the checker object's field \c Name, or through \c
- /// CheckerManager::getCurrentCheckName within the checker's registry
+ /// CheckerManager::getCurrentCheckerName within the checker's registry
/// function.
/// Checker options are retrieved in the following format:
/// `-analyzer-config CheckerName:OptionName=Value.
@@ -350,7 +359,7 @@ public:
/// If an option value is not provided, returns the given \p DefaultVal.
/// @param [in] CheckerName The *full name* of the checker. One may retrieve
/// this from the checker object's field \c Name, or through \c
- /// CheckerManager::getCurrentCheckName within the checker's registry
+ /// CheckerManager::getCurrentCheckerName within the checker's registry
/// function.
/// Checker options are retrieved in the following format:
/// `-analyzer-config CheckerName:OptionName=Value.
@@ -404,6 +413,43 @@ inline UserModeKind AnalyzerOptions::getUserMode() const {
return K.getValue();
}
+inline std::vector<StringRef>
+AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental) {
+ static constexpr llvm::StringLiteral StaticAnalyzerCheckerNames[] = {
+#define GET_CHECKERS
+#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \
+ llvm::StringLiteral(FULLNAME),
+#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
+#undef CHECKER
+#undef GET_CHECKERS
+ };
+ std::vector<StringRef> Checkers;
+ for (StringRef CheckerName : StaticAnalyzerCheckerNames) {
+ if (!CheckerName.startswith("debug.") &&
+ (IncludeExperimental || !CheckerName.startswith("alpha.")))
+ Checkers.push_back(CheckerName);
+ }
+ return Checkers;
+}
+
+inline std::vector<StringRef>
+AnalyzerOptions::getRegisteredPackages(bool IncludeExperimental) {
+ static constexpr llvm::StringLiteral StaticAnalyzerPackageNames[] = {
+#define GET_PACKAGES
+#define PACKAGE(FULLNAME) llvm::StringLiteral(FULLNAME),
+#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
+#undef PACKAGE
+#undef GET_PACKAGES
+ };
+ std::vector<StringRef> Packages;
+ for (StringRef PackageName : StaticAnalyzerPackageNames) {
+ if (PackageName != "debug" &&
+ (IncludeExperimental || PackageName != "alpha"))
+ Packages.push_back(PackageName);
+ }
+ return Packages;
+}
+
} // namespace clang
#endif // LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index d30ad19b20f8..e94b544172a0 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -14,10 +14,10 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTER_H
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
@@ -70,59 +70,253 @@ class SValBuilder;
using DiagnosticForConsumerMapTy =
llvm::DenseMap<PathDiagnosticConsumer *, std::unique_ptr<PathDiagnostic>>;
-/// This class provides an interface through which checkers can create
-/// individual bug reports.
-class BugReport : public llvm::ilist_node<BugReport> {
+/// Interface for classes constructing Stack hints.
+///
+/// If a PathDiagnosticEvent occurs in a different frame than the final
+/// diagnostic the hints can be used to summarize the effect of the call.
+class StackHintGenerator {
public:
- class NodeResolver {
- virtual void anchor();
+ virtual ~StackHintGenerator() = 0;
- public:
- virtual ~NodeResolver() = default;
+ /// Construct the Diagnostic message for the given ExplodedNode.
+ virtual std::string getMessage(const ExplodedNode *N) = 0;
+};
- virtual const ExplodedNode*
- getOriginalNode(const ExplodedNode *N) = 0;
- };
+/// 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;
- using ranges_iterator = const SourceRange *;
- using VisitorList = SmallVector<std::unique_ptr<BugReporterVisitor>, 8>;
- using visitor_iterator = VisitorList::iterator;
- using ExtraTextList = SmallVector<StringRef, 2>;
- using NoteList = SmallVector<std::shared_ptr<PathDiagnosticNotePiece>, 4>;
+public:
+ StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
+ ~StackHintGeneratorForSymbol() override = default;
+
+ /// Search the call expression for the symbol Sym and dispatch the
+ /// 'getMessageForX()' methods to construct a specific message.
+ std::string getMessage(const ExplodedNode *N) override;
+
+ /// 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;
+ }
+};
+
+/// This class provides an interface through which checkers can create
+/// individual bug reports.
+class BugReport {
+public:
+ enum class Kind { Basic, PathSensitive };
protected:
friend class BugReportEquivClass;
friend class BugReporter;
+ Kind K;
const BugType& BT;
- const Decl *DeclWithIssue = nullptr;
std::string ShortDescription;
std::string Description;
+
+ SmallVector<SourceRange, 4> Ranges;
+ SmallVector<std::shared_ptr<PathDiagnosticNotePiece>, 4> Notes;
+ SmallVector<FixItHint, 4> Fixits;
+
+ BugReport(Kind kind, const BugType &bt, StringRef desc)
+ : K(kind), BT(bt), Description(desc) {}
+
+ BugReport(Kind K, const BugType &BT, StringRef ShortDescription,
+ StringRef Description)
+ : K(K), BT(BT), ShortDescription(ShortDescription),
+ Description(Description) {}
+
+public:
+ virtual ~BugReport() = default;
+
+ Kind getKind() const { return K; }
+
+ const BugType& getBugType() const { return BT; }
+
+ /// A verbose warning message that is appropriate for displaying next to
+ /// the source code that introduces the problem. The description should be
+ /// at least a full sentence starting with a capital letter. The period at
+ /// the end of the warning is traditionally omitted. If the description
+ /// consists of multiple sentences, periods between the sentences are
+ /// encouraged, but the period at the end of the description is still omitted.
+ StringRef getDescription() const { return Description; }
+
+ /// A short general warning message that is appropriate for displaying in
+ /// the list of all reported bugs. It should describe what kind of bug is found
+ /// but does not need to try to go into details of that specific bug.
+ /// Grammatical conventions of getDescription() apply here as well.
+ StringRef getShortDescription(bool UseFallback = true) const {
+ if (ShortDescription.empty() && UseFallback)
+ return Description;
+ return ShortDescription;
+ }
+
+ /// The primary location of the bug report that points at the undesirable
+ /// behavior in the code. UIs should attach the warning description to this
+ /// location. The warning description should describe the bad behavior
+ /// at this location.
+ virtual PathDiagnosticLocation getLocation() const = 0;
+
+ /// The smallest declaration that contains the bug location.
+ /// This is purely cosmetic; the declaration can be displayed to the user
+ /// but it does not affect whether the report is emitted.
+ virtual const Decl *getDeclWithIssue() const = 0;
+
+ /// Get the location on which the report should be uniqued. Two warnings are
+ /// considered to be equivalent whenever they have the same bug types,
+ /// descriptions, and uniqueing locations. Out of a class of equivalent
+ /// warnings only one gets displayed to the user. For most warnings the
+ /// uniqueing location coincides with their location, but sometimes
+ /// it makes sense to use different locations. For example, a leak
+ /// checker can place the warning at the location where the last reference
+ /// to the leaking resource is dropped but at the same time unique the warning
+ /// by where that resource is acquired (allocated).
+ virtual PathDiagnosticLocation getUniqueingLocation() const = 0;
+
+ /// Get the declaration that corresponds to (usually contains) the uniqueing
+ /// location. This is not actively used for uniqueing, i.e. otherwise
+ /// identical reports that have different uniqueing decls will be considered
+ /// equivalent.
+ virtual const Decl *getUniqueingDecl() const = 0;
+
+ /// Add new item to the list of additional notes that need to be attached to
+ /// this report. If the report is path-sensitive, these notes will not be
+ /// displayed as part of the execution path explanation, but will be displayed
+ /// separately. Use bug visitors if you need to add an extra path note.
+ void addNote(StringRef Msg, const PathDiagnosticLocation &Pos,
+ ArrayRef<SourceRange> Ranges = {}) {
+ auto P = std::make_shared<PathDiagnosticNotePiece>(Pos, Msg);
+
+ for (const auto &R : Ranges)
+ P->addRange(R);
+
+ Notes.push_back(std::move(P));
+ }
+
+ ArrayRef<std::shared_ptr<PathDiagnosticNotePiece>> getNotes() {
+ return Notes;
+ }
+
+ /// Add a range to a bug report.
+ ///
+ /// Ranges are used to highlight regions of interest in the source code.
+ /// They should be at the same source code line as the BugReport location.
+ /// By default, the source range of the statement corresponding to the error
+ /// node will be used; add a single invalid range to specify absence of
+ /// ranges.
+ void addRange(SourceRange R) {
+ assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used "
+ "to specify that the report does not have a range.");
+ Ranges.push_back(R);
+ }
+
+ /// Get the SourceRanges associated with the report.
+ virtual ArrayRef<SourceRange> getRanges() const {
+ return Ranges;
+ }
+
+ /// Add a fix-it hint to the bug report.
+ ///
+ /// Fix-it hints are the suggested edits to the code that would resolve
+ /// the problem explained by the bug report. Fix-it hints should be
+ /// as conservative as possible because it is not uncommon for the user
+ /// to blindly apply all fixits to their project. Note that it is very hard
+ /// to produce a good fix-it hint for most path-sensitive warnings.
+ void addFixItHint(const FixItHint &F) {
+ Fixits.push_back(F);
+ }
+
+ llvm::ArrayRef<FixItHint> getFixits() const { return Fixits; }
+
+ /// Reports are uniqued to ensure that we do not emit multiple diagnostics
+ /// for each bug.
+ virtual void Profile(llvm::FoldingSetNodeID& hash) const = 0;
+};
+
+class BasicBugReport : public BugReport {
PathDiagnosticLocation Location;
- PathDiagnosticLocation UniqueingLocation;
- const Decl *UniqueingDecl;
+ const Decl *DeclWithIssue = nullptr;
+
+public:
+ BasicBugReport(const BugType &bt, StringRef desc, PathDiagnosticLocation l)
+ : BugReport(Kind::Basic, bt, desc), Location(l) {}
+
+ static bool classof(const BugReport *R) {
+ return R->getKind() == Kind::Basic;
+ }
+
+ PathDiagnosticLocation getLocation() const override {
+ assert(Location.isValid());
+ return Location;
+ }
+
+ const Decl *getDeclWithIssue() const override {
+ return DeclWithIssue;
+ }
+
+ PathDiagnosticLocation getUniqueingLocation() const override {
+ return getLocation();
+ }
+
+ const Decl *getUniqueingDecl() const override {
+ return getDeclWithIssue();
+ }
+
+ /// 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;
+ }
+ void Profile(llvm::FoldingSetNodeID& hash) const override;
+};
+
+class PathSensitiveBugReport : public BugReport {
+public:
+ using VisitorList = SmallVector<std::unique_ptr<BugReporterVisitor>, 8>;
+ using visitor_iterator = VisitorList::iterator;
+ using visitor_range = llvm::iterator_range<visitor_iterator>;
+
+protected:
+ /// The ExplodedGraph node against which the report was thrown. It corresponds
+ /// to the end of the execution path that demonstrates the bug.
const ExplodedNode *ErrorNode = nullptr;
- SmallVector<SourceRange, 4> Ranges;
- ExtraTextList ExtraText;
- NoteList Notes;
- using Symbols = llvm::DenseSet<SymbolRef>;
- using Regions = llvm::DenseSet<const MemRegion *>;
+ /// The range that corresponds to ErrorNode's program point. It is usually
+ /// highlighted in the report.
+ const SourceRange ErrorNodeRange;
+
+ /// Profile to identify equivalent bug reports for error report coalescing.
/// A (stack of) 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.
/// The stack is largely used by BugReporter when generating PathDiagnostics
/// for multiple PathDiagnosticConsumers.
- SmallVector<Symbols *, 2> interestingSymbols;
+ llvm::DenseMap<SymbolRef, bugreporter::TrackingKind> InterestingSymbols;
/// A (stack of) 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.
/// The stack is largely used by BugReporter when generating PathDiagnostics
/// for multiple PathDiagnosticConsumers.
- SmallVector<Regions *, 2> interestingRegions;
+ llvm::DenseMap<const MemRegion *, bugreporter::TrackingKind>
+ InterestingRegions;
/// A set of location contexts that correspoind to call sites which should be
/// considered "interesting".
@@ -156,66 +350,58 @@ protected:
/// Conditions we're already tracking.
llvm::SmallSet<const ExplodedNode *, 4> TrackedConditions;
-private:
- // Used internally by BugReporter.
- Symbols &getInterestingSymbols();
- Regions &getInterestingRegions();
-
- void lazyInitializeInterestingSets();
- void pushInterestingSymbolsAndRegions();
- void popInterestingSymbolsAndRegions();
-
-public:
- BugReport(const BugType& bt, StringRef desc, const ExplodedNode *errornode)
- : BT(bt), Description(desc), ErrorNode(errornode) {}
+ /// Reports with different uniqueing locations are considered to be different
+ /// for the purposes of deduplication.
+ PathDiagnosticLocation UniqueingLocation;
+ const Decl *UniqueingDecl;
- BugReport(const BugType& bt, StringRef shortDesc, StringRef desc,
- const ExplodedNode *errornode)
- : BT(bt), ShortDescription(shortDesc), Description(desc),
- ErrorNode(errornode) {}
+ const Stmt *getStmt() const;
- BugReport(const BugType &bt, StringRef desc, PathDiagnosticLocation l)
- : BT(bt), Description(desc), Location(l) {}
+ /// If an 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.
+ // FIXME: Allow shared_ptr keys in DenseMap?
+ std::map<PathDiagnosticPieceRef, std::unique_ptr<StackHintGenerator>>
+ StackHints;
- /// Create a BugReport with a custom uniqueing location.
+public:
+ PathSensitiveBugReport(const BugType &bt, StringRef desc,
+ const ExplodedNode *errorNode)
+ : BugReport(Kind::PathSensitive, bt, desc), ErrorNode(errorNode),
+ ErrorNodeRange(getStmt() ? getStmt()->getSourceRange()
+ : SourceRange()) {}
+
+ PathSensitiveBugReport(const BugType &bt, StringRef shortDesc, StringRef desc,
+ const ExplodedNode *errorNode)
+ : BugReport(Kind::PathSensitive, bt, shortDesc, desc),
+ ErrorNode(errorNode),
+ ErrorNodeRange(getStmt() ? getStmt()->getSourceRange()
+ : SourceRange()) {}
+
+ /// Create a PathSensitiveBugReport 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, const Decl *DeclToUnique)
- : BT(bt), Description(desc), UniqueingLocation(LocationToUnique),
- UniqueingDecl(DeclToUnique), ErrorNode(errornode) {}
-
- virtual ~BugReport();
-
- const BugType& getBugType() const { return BT; }
- //BugType& getBugType() { return BT; }
+ PathSensitiveBugReport(BugType &bt, StringRef desc,
+ const ExplodedNode *errorNode,
+ PathDiagnosticLocation LocationToUnique,
+ const Decl *DeclToUnique)
+ : BugReport(Kind::PathSensitive, bt, desc), ErrorNode(errorNode),
+ ErrorNodeRange(getStmt() ? getStmt()->getSourceRange() : SourceRange()),
+ UniqueingLocation(LocationToUnique), UniqueingDecl(DeclToUnique) {
+ assert(errorNode);
+ }
- /// True when the report has an execution path associated with it.
- ///
- /// A report is said to be path-sensitive if it was thrown against a
- /// particular exploded node in the path-sensitive analysis graph.
- /// Path-sensitive reports have their intermediate path diagnostics
- /// auto-generated, perhaps with the help of checker-defined visitors,
- /// and may contain extra notes.
- /// Path-insensitive reports consist only of a single warning message
- /// in a specific location, and perhaps extra notes.
- /// Path-sensitive checkers are allowed to throw path-insensitive reports.
- bool isPathSensitive() const { return ErrorNode != nullptr; }
+ static bool classof(const BugReport *R) {
+ return R->getKind() == Kind::PathSensitive;
+ }
const ExplodedNode *getErrorNode() const { return ErrorNode; }
- StringRef getDescription() const { return Description; }
-
- StringRef getShortDescription(bool UseFallback = true) const {
- if (ShortDescription.empty() && UseFallback)
- return Description;
- return ShortDescription;
- }
-
/// Indicates whether or not any path pruning should take place
/// when generating a PathDiagnostic from this BugReport.
bool shouldPrunePath() const { return !DoNotPrunePath; }
@@ -223,15 +409,54 @@ public:
/// Disable all path pruning when generating a PathDiagnostic.
void disablePathPruning() { DoNotPrunePath = true; }
- void markInteresting(SymbolRef sym);
- void markInteresting(const MemRegion *R);
- void markInteresting(SVal V);
+ /// Get the location on which the report should be uniqued.
+ PathDiagnosticLocation getUniqueingLocation() const override {
+ return UniqueingLocation;
+ }
+
+ /// Get the declaration containing the uniqueing location.
+ const Decl *getUniqueingDecl() const override {
+ return UniqueingDecl;
+ }
+
+ const Decl *getDeclWithIssue() const override;
+
+ ArrayRef<SourceRange> getRanges() const override;
+
+ PathDiagnosticLocation getLocation() const override;
+
+ /// Marks a symbol as interesting. Different kinds of interestingness will
+ /// be processed differently by visitors (e.g. if the tracking kind is
+ /// condition, will append "will be used as a condition" to the message).
+ void markInteresting(SymbolRef sym, bugreporter::TrackingKind TKind =
+ bugreporter::TrackingKind::Thorough);
+
+ /// Marks a region as interesting. Different kinds of interestingness will
+ /// be processed differently by visitors (e.g. if the tracking kind is
+ /// condition, will append "will be used as a condition" to the message).
+ void markInteresting(
+ const MemRegion *R,
+ bugreporter::TrackingKind TKind = bugreporter::TrackingKind::Thorough);
+
+ /// Marks a symbolic value as interesting. Different kinds of interestingness
+ /// will be processed differently by visitors (e.g. if the tracking kind is
+ /// condition, will append "will be used as a condition" to the message).
+ void markInteresting(SVal V, bugreporter::TrackingKind TKind =
+ bugreporter::TrackingKind::Thorough);
void markInteresting(const LocationContext *LC);
- bool isInteresting(SymbolRef sym);
- bool isInteresting(const MemRegion *R);
- bool isInteresting(SVal V);
- bool isInteresting(const LocationContext *LC);
+ bool isInteresting(SymbolRef sym) const;
+ bool isInteresting(const MemRegion *R) const;
+ bool isInteresting(SVal V) const;
+ bool isInteresting(const LocationContext *LC) const;
+
+ Optional<bugreporter::TrackingKind>
+ getInterestingnessKind(SymbolRef sym) const;
+
+ Optional<bugreporter::TrackingKind>
+ getInterestingnessKind(const MemRegion *R) const;
+
+ Optional<bugreporter::TrackingKind> getInterestingnessKind(SVal V) const;
/// Returns whether or not this report should be considered valid.
///
@@ -254,87 +479,10 @@ public:
Invalidations.insert(std::make_pair(Tag, Data));
}
- /// 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;
- }
-
- /// Add new item to the list of additional notes that need to be attached to
- /// this path-insensitive report. If you want to add extra notes to a
- /// path-sensitive report, you need to use a BugReporterVisitor because it
- /// allows you to specify where exactly in the auto-generated path diagnostic
- /// the extra note should appear.
- void addNote(StringRef Msg, const PathDiagnosticLocation &Pos,
- ArrayRef<SourceRange> Ranges) {
- auto P = std::make_shared<PathDiagnosticNotePiece>(Pos, Msg);
-
- for (const auto &R : Ranges)
- P->addRange(R);
-
- Notes.push_back(std::move(P));
- }
-
- // FIXME: Instead of making an override, we could have default-initialized
- // Ranges with {}, however it crashes the MSVC 2013 compiler.
- void addNote(StringRef Msg, const PathDiagnosticLocation &Pos) {
- std::vector<SourceRange> Ranges;
- addNote(Msg, Pos, Ranges);
- }
-
- virtual const NoteList &getNotes() {
- return Notes;
- }
-
- /// This allows for addition of meta data to the diagnostic.
- ///
- /// Currently, only the HTMLDiagnosticClient knows how to display it.
- void addExtraText(StringRef S) {
- ExtraText.push_back(S);
- }
-
- virtual const ExtraTextList &getExtraText() {
- return ExtraText;
- }
-
- /// Return the "definitive" location of the reported bug.
- ///
- /// While a bug can span an entire path, usually there is a specific
- /// location that can be used to identify where the key issue occurred.
- /// This location is used by clients rendering diagnostics.
- virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const;
-
- /// Get the location on which the report should be uniqued.
- PathDiagnosticLocation getUniqueingLocation() const {
- return UniqueingLocation;
- }
-
- /// Get the declaration containing the uniqueing location.
- const Decl *getUniqueingDecl() const {
- return UniqueingDecl;
- }
-
- const Stmt *getStmt() const;
-
- /// Add a range to a bug report.
- ///
- /// Ranges are used to highlight regions of interest in the source code.
- /// They should be at the same source code line as the BugReport location.
- /// By default, the source range of the statement corresponding to the error
- /// node will be used; add a single invalid range to specify absence of
- /// ranges.
- void addRange(SourceRange R) {
- assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used "
- "to specify that the report does not have a range.");
- Ranges.push_back(R);
- }
-
- /// Get the SourceRanges associated with the report.
- virtual llvm::iterator_range<ranges_iterator> getRanges();
+ /// Profile to identify equivalent bug reports for error report coalescing.
+ /// Reports are uniqued to ensure that we do not emit multiple diagnostics
+ /// for each bug.
+ void Profile(llvm::FoldingSetNodeID &hash) const override;
/// Add custom or predefined bug report visitors to this report.
///
@@ -351,6 +499,7 @@ public:
/// Iterators through the custom diagnostic visitors.
visitor_iterator visitor_begin() { return Callbacks.begin(); }
visitor_iterator visitor_end() { return Callbacks.end(); }
+ visitor_range visitors() { return {visitor_begin(), visitor_end()}; }
/// Notes that the condition of the CFGBlock associated with \p Cond is
/// being tracked.
@@ -359,10 +508,25 @@ public:
return TrackedConditions.insert(Cond).second;
}
- /// Profile to identify equivalent bug reports for error report coalescing.
- /// Reports are uniqued to ensure that we do not emit multiple diagnostics
- /// for each bug.
- virtual void Profile(llvm::FoldingSetNodeID& hash) const;
+ void addCallStackHint(PathDiagnosticPieceRef Piece,
+ std::unique_ptr<StackHintGenerator> StackHint) {
+ StackHints[Piece] = std::move(StackHint);
+ }
+
+ bool hasCallStackHint(PathDiagnosticPieceRef Piece) const {
+ return StackHints.count(Piece) > 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(PathDiagnosticPieceRef Piece,
+ const ExplodedNode *N) const {
+ auto I = StackHints.find(Piece);
+ if (I != StackHints.end())
+ return I->second->getMessage(N);
+ return "";
+ }
};
//===----------------------------------------------------------------------===//
@@ -373,29 +537,21 @@ class BugReportEquivClass : public llvm::FoldingSetNode {
friend class BugReporter;
/// List of *owned* BugReport objects.
- llvm::ilist<BugReport> Reports;
+ llvm::SmallVector<std::unique_ptr<BugReport>, 4> Reports;
- void AddReport(std::unique_ptr<BugReport> R) {
- Reports.push_back(R.release());
+ void AddReport(std::unique_ptr<BugReport> &&R) {
+ Reports.push_back(std::move(R));
}
public:
BugReportEquivClass(std::unique_ptr<BugReport> R) { AddReport(std::move(R)); }
- ~BugReportEquivClass();
+
+ ArrayRef<std::unique_ptr<BugReport>> getReports() const { return Reports; }
void Profile(llvm::FoldingSetNodeID& ID) const {
assert(!Reports.empty());
- Reports.front().Profile(ID);
+ Reports.front()->Profile(ID);
}
-
- using iterator = llvm::ilist<BugReport>::iterator;
- using const_iterator = llvm::ilist<BugReport>::const_iterator;
-
- iterator begin() { return Reports.begin(); }
- iterator end() { return Reports.end(); }
-
- const_iterator begin() const { return Reports.begin(); }
- const_iterator end() const { return Reports.end(); }
};
//===----------------------------------------------------------------------===//
@@ -404,9 +560,8 @@ public:
class BugReporterData {
public:
- virtual ~BugReporterData();
+ virtual ~BugReporterData() = default;
- virtual DiagnosticsEngine& getDiagnostic() = 0;
virtual ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() = 0;
virtual ASTContext &getASTContext() = 0;
virtual SourceManager &getSourceManager() = 0;
@@ -419,60 +574,29 @@ public:
///
/// The base class is used for generating path-insensitive
class BugReporter {
-public:
- enum Kind { BaseBRKind, GRBugReporterKind };
-
private:
- using BugTypesTy = llvm::ImmutableSet<BugType *>;
-
- BugTypesTy::Factory F;
- BugTypesTy BugTypes;
-
- const Kind kind;
BugReporterData& D;
/// Generate and flush the diagnostics for the given bug report.
void FlushReport(BugReportEquivClass& EQ);
- /// Generate the diagnostics for the given bug report.
- std::unique_ptr<DiagnosticForConsumerMapTy>
- generateDiagnosticForConsumerMap(BugReport *exampleReport,
- ArrayRef<PathDiagnosticConsumer *> consumers,
- ArrayRef<BugReport *> bugReports);
-
/// The set of bug reports tracked by the BugReporter.
llvm::FoldingSet<BugReportEquivClass> EQClasses;
/// A vector of BugReports for tracking the allocated pointers and cleanup.
std::vector<BugReportEquivClass *> EQClassesVector;
-protected:
- BugReporter(BugReporterData& d, Kind k)
- : BugTypes(F.getEmptySet()), kind(k), D(d) {}
-
public:
- BugReporter(BugReporterData& d)
- : BugTypes(F.getEmptySet()), kind(BaseBRKind), D(d) {}
+ BugReporter(BugReporterData &d) : D(d) {}
virtual ~BugReporter();
/// Generate and flush diagnostics for all bug reports.
void FlushReports();
- Kind getKind() const { return kind; }
-
- DiagnosticsEngine& getDiagnostic() {
- return D.getDiagnostic();
- }
-
ArrayRef<PathDiagnosticConsumer*> getPathDiagnosticConsumers() {
return D.getPathDiagnosticConsumers();
}
- /// Iterator over the set of BugTypes tracked by the BugReporter.
- using iterator = BugTypesTy::iterator;
- iterator begin() { return BugTypes.begin(); }
- iterator end() { return BugTypes.end(); }
-
/// Iterator over the set of BugReports tracked by the BugReporter.
using EQClasses_iterator = llvm::FoldingSet<BugReportEquivClass>::iterator;
EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); }
@@ -480,126 +604,116 @@ public:
ASTContext &getContext() { return D.getASTContext(); }
- SourceManager &getSourceManager() { return D.getSourceManager(); }
-
- AnalyzerOptions &getAnalyzerOptions() { return D.getAnalyzerOptions(); }
-
- virtual std::unique_ptr<DiagnosticForConsumerMapTy>
- generatePathDiagnostics(ArrayRef<PathDiagnosticConsumer *> consumers,
- ArrayRef<BugReport *> &bugReports) {
- return {};
- }
+ const SourceManager &getSourceManager() { return D.getSourceManager(); }
- void Register(const BugType *BT);
+ const AnalyzerOptions &getAnalyzerOptions() { return D.getAnalyzerOptions(); }
/// Add the given report to the set of reports tracked by BugReporter.
///
/// The reports are usually generated by the checkers. Further, they are
/// folded based on the profile value, which is done to coalesce similar
/// reports.
- void emitReport(std::unique_ptr<BugReport> R);
+ virtual void emitReport(std::unique_ptr<BugReport> R);
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker,
StringRef BugName, StringRef BugCategory,
StringRef BugStr, PathDiagnosticLocation Loc,
- ArrayRef<SourceRange> Ranges = None);
+ ArrayRef<SourceRange> Ranges = None,
+ ArrayRef<FixItHint> Fixits = None);
- void EmitBasicReport(const Decl *DeclWithIssue, CheckName CheckName,
+ void EmitBasicReport(const Decl *DeclWithIssue, CheckerNameRef CheckerName,
StringRef BugName, StringRef BugCategory,
StringRef BugStr, PathDiagnosticLocation Loc,
- ArrayRef<SourceRange> Ranges = None);
+ ArrayRef<SourceRange> Ranges = None,
+ ArrayRef<FixItHint> Fixits = None);
private:
llvm::StringMap<BugType *> StrBugTypes;
/// Returns a BugType that is associated with the given name and
/// category.
- BugType *getBugTypeForName(CheckName CheckName, StringRef name,
+ BugType *getBugTypeForName(CheckerNameRef CheckerName, StringRef name,
StringRef category);
+
+ virtual BugReport *
+ findReportInEquivalenceClass(BugReportEquivClass &eqClass,
+ SmallVectorImpl<BugReport *> &bugReports) {
+ return eqClass.getReports()[0].get();
+ }
+
+protected:
+ /// Generate the diagnostics for the given bug report.
+ virtual std::unique_ptr<DiagnosticForConsumerMapTy>
+ generateDiagnosticForConsumerMap(BugReport *exampleReport,
+ ArrayRef<PathDiagnosticConsumer *> consumers,
+ ArrayRef<BugReport *> bugReports);
};
/// GRBugReporter is used for generating path-sensitive reports.
-class GRBugReporter : public BugReporter {
+class PathSensitiveBugReporter final : public BugReporter {
ExprEngine& Eng;
-public:
- GRBugReporter(BugReporterData& d, ExprEngine& eng)
- : BugReporter(d, GRBugReporterKind), Eng(eng) {}
+ BugReport *findReportInEquivalenceClass(
+ BugReportEquivClass &eqClass,
+ SmallVectorImpl<BugReport *> &bugReports) override;
- ~GRBugReporter() override;
+ /// Generate the diagnostics for the given bug report.
+ std::unique_ptr<DiagnosticForConsumerMapTy>
+ generateDiagnosticForConsumerMap(BugReport *exampleReport,
+ ArrayRef<PathDiagnosticConsumer *> consumers,
+ ArrayRef<BugReport *> bugReports) override;
+public:
+ PathSensitiveBugReporter(BugReporterData& d, ExprEngine& eng)
+ : BugReporter(d), Eng(eng) {}
/// getGraph - Get the exploded graph created by the analysis engine
/// for the analyzed method or function.
- ExplodedGraph &getGraph();
+ const ExplodedGraph &getGraph() const;
/// getStateManager - Return the state manager used by the analysis
/// engine.
- ProgramStateManager &getStateManager();
+ ProgramStateManager &getStateManager() const;
/// \p bugReports A set of bug reports within a *single* equivalence class
///
/// \return A mapping from consumers to the corresponding diagnostics.
/// Iterates through the bug reports within a single equivalence class,
/// stops at a first non-invalidated report.
- std::unique_ptr<DiagnosticForConsumerMapTy>
- generatePathDiagnostics(ArrayRef<PathDiagnosticConsumer *> consumers,
- ArrayRef<BugReport *> &bugReports) override;
+ std::unique_ptr<DiagnosticForConsumerMapTy> generatePathDiagnostics(
+ ArrayRef<PathDiagnosticConsumer *> consumers,
+ ArrayRef<PathSensitiveBugReport *> &bugReports);
- /// classof - Used by isa<>, cast<>, and dyn_cast<>.
- static bool classof(const BugReporter* R) {
- return R->getKind() == GRBugReporterKind;
- }
+ void emitReport(std::unique_ptr<BugReport> R) override;
};
-class NodeMapClosure : public BugReport::NodeResolver {
- InterExplodedGraphMap &M;
-
-public:
- NodeMapClosure(InterExplodedGraphMap &m) : M(m) {}
-
- const ExplodedNode *getOriginalNode(const ExplodedNode *N) override {
- return M.lookup(N);
- }
-};
-
class BugReporterContext {
- GRBugReporter &BR;
- NodeMapClosure NMC;
+ PathSensitiveBugReporter &BR;
virtual void anchor();
public:
- BugReporterContext(GRBugReporter &br, InterExplodedGraphMap &Backmap)
- : BR(br), NMC(Backmap) {}
+ BugReporterContext(PathSensitiveBugReporter &br) : BR(br) {}
virtual ~BugReporterContext() = default;
- GRBugReporter& getBugReporter() { return BR; }
+ PathSensitiveBugReporter& getBugReporter() { return BR; }
- ExplodedGraph &getGraph() { return BR.getGraph(); }
-
- ProgramStateManager& getStateManager() {
+ ProgramStateManager& getStateManager() const {
return BR.getStateManager();
}
- SValBuilder &getSValBuilder() {
- return getStateManager().getSValBuilder();
- }
-
- ASTContext &getASTContext() {
+ ASTContext &getASTContext() const {
return BR.getContext();
}
- SourceManager& getSourceManager() {
+ const SourceManager& getSourceManager() const {
return BR.getSourceManager();
}
- AnalyzerOptions &getAnalyzerOptions() {
+ const AnalyzerOptions &getAnalyzerOptions() const {
return BR.getAnalyzerOptions();
}
-
- NodeMapClosure& getNodeResolver() { return NMC; }
};
@@ -648,7 +762,7 @@ public:
public:
const NoteTag *makeNoteTag(Callback &&Cb, bool IsPrunable = false) {
- // We cannot use make_unique because we cannot access the private
+ // We cannot use std::make_unique because we cannot access the private
// constructor from inside it.
std::unique_ptr<NoteTag> T(new NoteTag(std::move(Cb), IsPrunable));
Tags.push_back(std::move(T));
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
index ef5d327d39da..de0ee5de81b5 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -33,11 +33,12 @@ class Stmt;
namespace ento {
-class BugReport;
+class PathSensitiveBugReport;
class BugReporterContext;
class ExplodedNode;
class MemRegion;
class PathDiagnosticPiece;
+using PathDiagnosticPieceRef = std::shared_ptr<PathDiagnosticPiece>;
/// BugReporterVisitors are used to add custom diagnostics along a path.
class BugReporterVisitor : public llvm::FoldingSetNode {
@@ -57,32 +58,68 @@ public:
///
/// The last parameter can be used to register a new visitor with the given
/// BugReport while processing a node.
- virtual std::shared_ptr<PathDiagnosticPiece>
- VisitNode(const ExplodedNode *Succ,
- BugReporterContext &BRC, BugReport &BR) = 0;
+ virtual PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) = 0;
/// Last function called on the visitor, no further calls to VisitNode
/// would follow.
virtual void finalizeVisitor(BugReporterContext &BRC,
const ExplodedNode *EndPathNode,
- BugReport &BR);
+ PathSensitiveBugReport &BR);
/// Provide custom definition for the final diagnostic piece on the
/// path - the piece, which is displayed before the path is expanded.
///
/// NOTE that this function can be implemented on at most one used visitor,
/// and otherwise it crahes at runtime.
- virtual std::shared_ptr<PathDiagnosticPiece>
- getEndPath(BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR);
+ virtual PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ PathSensitiveBugReport &BR);
virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
/// Generates the default final diagnostic piece.
- static std::shared_ptr<PathDiagnosticPiece>
- getDefaultEndPath(BugReporterContext &BRC, const ExplodedNode *N,
- BugReport &BR);
+ static PathDiagnosticPieceRef
+ getDefaultEndPath(const BugReporterContext &BRC, const ExplodedNode *N,
+ const PathSensitiveBugReport &BR);
};
+namespace bugreporter {
+
+/// Specifies the type of tracking for an expression.
+enum class TrackingKind {
+ /// Default tracking kind -- specifies that as much information should be
+ /// gathered about the tracked expression value as possible.
+ Thorough,
+ /// Specifies that a more moderate tracking should be used for the expression
+ /// value. This will essentially make sure that functions relevant to the it
+ /// aren't pruned, but otherwise relies on the user reading the code or
+ /// following the arrows.
+ Condition
+};
+
+/// Attempts to add visitors to track expression value back to its point of
+/// origin.
+///
+/// \param N A node "downstream" from the evaluation of the statement.
+/// \param E The expression value which we are tracking
+/// \param R The bug report to which visitors should be attached.
+/// \param EnableNullFPSuppression Whether we should employ false positive
+/// suppression (inlined defensive checks, returned null).
+///
+/// \return Whether or not the function was able to add visitors for this
+/// statement. Note that returning \c true does not actually imply
+/// that any visitors were added.
+bool trackExpressionValue(const ExplodedNode *N, const Expr *E,
+ PathSensitiveBugReport &R,
+ TrackingKind TKind = TrackingKind::Thorough,
+ bool EnableNullFPSuppression = true);
+
+const Expr *getDerefExpr(const Stmt *S);
+
+} // namespace bugreporter
+
/// Finds last store into the given region,
/// which is different from a given symbolic value.
class FindLastStoreBRVisitor final : public BugReporterVisitor {
@@ -94,21 +131,34 @@ class FindLastStoreBRVisitor final : public BugReporterVisitor {
/// bug, we are going to employ false positive suppression.
bool EnableNullFPSuppression;
-public:
- /// Creates a visitor for every VarDecl inside a Stmt and registers it with
- /// the BugReport.
- static void registerStatementVarDecls(BugReport &BR, const Stmt *S,
- bool EnableNullFPSuppression);
+ using TrackingKind = bugreporter::TrackingKind;
+ TrackingKind TKind;
+ const StackFrameContext *OriginSFC;
+public:
+ /// \param V We're searching for the store where \c R received this value.
+ /// \param R The region we're tracking.
+ /// \param TKind May limit the amount of notes added to the bug report.
+ /// \param OriginSFC Only adds notes when the last store happened in a
+ /// different stackframe to this one. Disregarded if the tracking kind
+ /// is thorough.
+ /// This is useful, because for non-tracked regions, notes about
+ /// changes to its value in a nested stackframe could be pruned, and
+ /// this visitor can prevent that without polluting the bugpath too
+ /// much.
FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R,
- bool InEnableNullFPSuppression)
- : R(R), V(V), EnableNullFPSuppression(InEnableNullFPSuppression) {}
+ bool InEnableNullFPSuppression, TrackingKind TKind,
+ const StackFrameContext *OriginSFC = nullptr)
+ : R(R), V(V), EnableNullFPSuppression(InEnableNullFPSuppression),
+ TKind(TKind), OriginSFC(OriginSFC) {
+ assert(R);
+ }
void Profile(llvm::FoldingSetNodeID &ID) const override;
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
};
class TrackConstraintBRVisitor final : public BugReporterVisitor {
@@ -132,9 +182,9 @@ public:
/// to make all PathDiagnosticPieces created by this visitor.
static const char *getTag();
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
private:
/// Checks if the constraint is valid in the current state.
@@ -150,9 +200,9 @@ public:
ID.AddPointer(&x);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
/// If the statement is a message send expression with nil receiver, returns
/// the receiver expression. Returns NULL otherwise.
@@ -162,8 +212,10 @@ public:
/// Visitor that tries to report interesting diagnostics from conditions.
class ConditionBRVisitor final : public BugReporterVisitor {
// FIXME: constexpr initialization isn't supported by MSVC2013.
- static const char *const GenericTrueMessage;
- static const char *const GenericFalseMessage;
+ constexpr static llvm::StringLiteral GenericTrueMessage =
+ "Assuming the condition is true";
+ constexpr static llvm::StringLiteral GenericFalseMessage =
+ "Assuming the condition is false";
public:
void Profile(llvm::FoldingSetNodeID &ID) const override {
@@ -175,41 +227,44 @@ public:
/// to make all PathDiagnosticPieces created by this visitor.
static const char *getTag();
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
- std::shared_ptr<PathDiagnosticPiece> VisitNodeImpl(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR);
+ PathDiagnosticPieceRef VisitNodeImpl(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR);
- std::shared_ptr<PathDiagnosticPiece>
+ PathDiagnosticPieceRef
VisitTerminator(const Stmt *Term, const ExplodedNode *N,
- const CFGBlock *srcBlk, const CFGBlock *dstBlk, BugReport &R,
- BugReporterContext &BRC);
+ const CFGBlock *SrcBlk, const CFGBlock *DstBlk,
+ PathSensitiveBugReport &R, BugReporterContext &BRC);
- std::shared_ptr<PathDiagnosticPiece>
- VisitTrueTest(const Expr *Cond, BugReporterContext &BRC, BugReport &R,
- const ExplodedNode *N, bool TookTrue);
+ PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &R,
+ const ExplodedNode *N, bool TookTrue);
- std::shared_ptr<PathDiagnosticPiece>
- VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR,
- BugReporterContext &BRC, BugReport &R, const ExplodedNode *N,
- bool TookTrue, bool IsAssuming);
+ PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &R,
+ const ExplodedNode *N, bool TookTrue,
+ bool IsAssuming);
- std::shared_ptr<PathDiagnosticPiece>
+ PathDiagnosticPieceRef
VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr,
- BugReporterContext &BRC, BugReport &R, const ExplodedNode *N,
- bool TookTrue, bool IsAssuming);
+ BugReporterContext &BRC, PathSensitiveBugReport &R,
+ const ExplodedNode *N, bool TookTrue, bool IsAssuming);
- std::shared_ptr<PathDiagnosticPiece>
- VisitTrueTest(const Expr *Cond, const MemberExpr *ME, BugReporterContext &BRC,
- BugReport &R, const ExplodedNode *N, bool TookTrue,
- bool IsAssuming);
+ PathDiagnosticPieceRef VisitTrueTest(const Expr *Cond, const MemberExpr *ME,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &R,
+ const ExplodedNode *N, bool TookTrue,
+ bool IsAssuming);
- std::shared_ptr<PathDiagnosticPiece>
+ PathDiagnosticPieceRef
VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr,
- BugReporterContext &BRC, BugReport &R,
+ BugReporterContext &BRC, PathSensitiveBugReport &R,
const ExplodedNode *N, bool TookTrue);
/// Tries to print the value of the given expression.
@@ -228,7 +283,7 @@ public:
const Expr *ParentEx,
raw_ostream &Out,
BugReporterContext &BRC,
- BugReport &R,
+ PathSensitiveBugReport &R,
const ExplodedNode *N,
Optional<bool> &prunable,
bool IsSameFieldName);
@@ -251,14 +306,13 @@ public:
ID.AddPointer(getTag());
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *,
- BugReporterContext &,
- BugReport &) override {
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *, BugReporterContext &,
+ PathSensitiveBugReport &) override {
return nullptr;
}
void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *N,
- BugReport &BR) override;
+ PathSensitiveBugReport &BR) override;
};
/// When a region containing undefined value or '0' value is passed
@@ -279,9 +333,9 @@ public:
ID.AddPointer(R);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
};
class SuppressInlineDefensiveChecksVisitor final : public BugReporterVisitor {
@@ -308,9 +362,9 @@ public:
/// to make all PathDiagnosticPieces created by this visitor.
static const char *getTag();
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
};
/// The bug visitor will walk all the nodes in a path and collect all the
@@ -326,12 +380,12 @@ public:
void Profile(llvm::FoldingSetNodeID &ID) const override;
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
void finalizeVisitor(BugReporterContext &BRC, const ExplodedNode *EndPathNode,
- BugReport &BR) override;
+ PathSensitiveBugReport &BR) override;
};
@@ -340,32 +394,11 @@ class TagVisitor : public BugReporterVisitor {
public:
void Profile(llvm::FoldingSetNodeID &ID) const override;
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &R) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &R) override;
};
-namespace bugreporter {
-
-/// Attempts to add visitors to track expression value back to its point of
-/// origin.
-///
-/// \param N A node "downstream" from the evaluation of the statement.
-/// \param E The expression value which we are tracking
-/// \param R The bug report to which visitors should be attached.
-/// \param EnableNullFPSuppression Whether we should employ false positive
-/// suppression (inlined defensive checks, returned null).
-///
-/// \return Whether or not the function was able to add visitors for this
-/// statement. Note that returning \c true does not actually imply
-/// that any visitors were added.
-bool trackExpressionValue(const ExplodedNode *N, const Expr *E, BugReport &R,
- bool EnableNullFPSuppression = true);
-
-const Expr *getDerefExpr(const Stmt *S);
-
-} // namespace bugreporter
-
} // namespace ento
} // namespace clang
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
index 324b5312e790..237053df7e44 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
@@ -28,8 +28,8 @@ class ExprEngine;
class BugType {
private:
- const CheckName Check;
- const std::string Name;
+ const CheckerNameRef CheckerName;
+ const std::string Description;
const std::string Category;
const CheckerBase *Checker;
bool SuppressOnSink;
@@ -37,28 +37,27 @@ private:
virtual void anchor();
public:
- BugType(CheckName Check, StringRef Name, StringRef Cat,
- bool SuppressOnSink=false)
- : Check(Check), Name(Name), Category(Cat), Checker(nullptr),
- SuppressOnSink(SuppressOnSink) {}
+ BugType(CheckerNameRef CheckerName, StringRef Name, StringRef Cat,
+ bool SuppressOnSink = false)
+ : CheckerName(CheckerName), Description(Name), Category(Cat),
+ Checker(nullptr), SuppressOnSink(SuppressOnSink) {}
BugType(const CheckerBase *Checker, StringRef Name, StringRef Cat,
- bool SuppressOnSink=false)
- : Check(Checker->getCheckName()), Name(Name), Category(Cat),
- Checker(Checker), SuppressOnSink(SuppressOnSink) {}
+ bool SuppressOnSink = false)
+ : CheckerName(Checker->getCheckerName()), Description(Name),
+ Category(Cat), Checker(Checker), SuppressOnSink(SuppressOnSink) {}
virtual ~BugType() = default;
- StringRef getName() const { return Name; }
+ StringRef getDescription() const { return Description; }
StringRef getCategory() const { return Category; }
- StringRef getCheckName() const {
- // FIXME: This is a workaround to ensure that the correct check name is used
- // The check names are set after the constructors are run.
+ StringRef getCheckerName() const {
+ // FIXME: This is a workaround to ensure that the correct checerk name is
+ // used. The checker names are set after the constructors are run.
// In case the BugType object is initialized in the checker's ctor
- // the Check field will be empty. To circumvent this problem we use
+ // the CheckerName field will be empty. To circumvent this problem we use
// CheckerBase whenever it is possible.
- StringRef CheckName =
- Checker ? Checker->getCheckName().getName() : Check.getName();
- assert(!CheckName.empty() && "Check name is not set properly.");
- return CheckName;
+ StringRef Ret = Checker ? Checker->getCheckerName() : CheckerName;
+ assert(!Ret.empty() && "Checker name is not set properly.");
+ return Ret;
}
/// isSuppressOnSink - Returns true if bug reports associated with this bug
@@ -71,8 +70,9 @@ class BuiltinBug : public BugType {
const std::string desc;
void anchor() override;
public:
- BuiltinBug(class CheckName check, const char *name, const char *description)
- : BugType(check, name, categories::LogicError), desc(description) {}
+ BuiltinBug(class CheckerNameRef checker, const char *name,
+ const char *description)
+ : BugType(checker, name, categories::LogicError), desc(description) {}
BuiltinBug(const CheckerBase *checker, const char *name,
const char *description)
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
index 85526eb49f0c..22c1a7dd98cc 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h
@@ -18,6 +18,7 @@ namespace clang {
extern const char * const MemoryRefCount;
extern const char * const MemoryError;
extern const char * const UnixAPI;
+ extern const char * const CXXObjectLifecycle;
}
}
}
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index d0fe15f8b896..0c7acdbc3a97 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -490,12 +490,12 @@ public:
} // end eval namespace
class CheckerBase : public ProgramPointTag {
- CheckName Name;
+ CheckerNameRef Name;
friend class ::clang::ento::CheckerManager;
public:
StringRef getTagDescription() const override;
- CheckName getCheckName() const;
+ CheckerNameRef getCheckerName() const;
/// See CheckerManager::runCheckersForPrintState.
virtual void printState(raw_ostream &Out, ProgramStateRef State,
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 6cc4baa1687f..38a9aaf72c27 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -90,21 +90,23 @@ enum PointerEscapeKind {
PSK_EscapeOther
};
-// This wrapper is used to ensure that only StringRefs originating from the
-// CheckerRegistry are used as check names. We want to make sure all check
-// name strings have a lifetime that keeps them alive at least until the path
-// diagnostics have been processed.
-class CheckName {
+/// This wrapper is used to ensure that only StringRefs originating from the
+/// CheckerRegistry are used as check names. We want to make sure all checker
+/// name strings have a lifetime that keeps them alive at least until the path
+/// diagnostics have been processed, since they are expected to be constexpr
+/// string literals (most likely generated by TblGen).
+class CheckerNameRef {
friend class ::clang::ento::CheckerRegistry;
StringRef Name;
- explicit CheckName(StringRef Name) : Name(Name) {}
+ explicit CheckerNameRef(StringRef Name) : Name(Name) {}
public:
- CheckName() = default;
+ CheckerNameRef() = default;
StringRef getName() const { return Name; }
+ operator StringRef() const { return Name; }
};
enum class ObjCMessageVisitKind {
@@ -117,7 +119,7 @@ class CheckerManager {
ASTContext &Context;
const LangOptions LangOpts;
AnalyzerOptions &AOptions;
- CheckName CurrentCheckName;
+ CheckerNameRef CurrentCheckerName;
public:
CheckerManager(ASTContext &Context, AnalyzerOptions &AOptions)
@@ -125,8 +127,8 @@ public:
~CheckerManager();
- void setCurrentCheckName(CheckName name) { CurrentCheckName = name; }
- CheckName getCurrentCheckName() const { return CurrentCheckName; }
+ void setCurrentCheckerName(CheckerNameRef name) { CurrentCheckerName = name; }
+ CheckerNameRef getCurrentCheckerName() const { return CurrentCheckerName; }
bool hasPathSensitiveCheckers() const;
@@ -162,7 +164,7 @@ public:
assert(!ref && "Checker already registered, use getChecker!");
CHECKER *checker = new CHECKER(std::forward<AT>(Args)...);
- checker->Name = CurrentCheckName;
+ checker->Name = CurrentCheckerName;
CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>));
CHECKER::_register(checker, *this);
ref = checker;
diff --git a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
index ef6e7e0f45d5..8601966c91e5 100644
--- a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
+++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
@@ -20,17 +20,19 @@ namespace clang {
class AnalyzerOptions;
class Preprocessor;
+namespace cross_tu {
+class CrossTranslationUnitContext;
+}
namespace ento {
class PathDiagnosticConsumer;
typedef std::vector<PathDiagnosticConsumer*> PathDiagnosticConsumers;
-#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN)\
-void CREATEFN(AnalyzerOptions &AnalyzerOpts,\
- PathDiagnosticConsumers &C,\
- const std::string &Prefix,\
- const Preprocessor &PP);
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \
+ void CREATEFN(AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, \
+ const std::string &Prefix, const Preprocessor &PP, \
+ const cross_tu::CrossTranslationUnitContext &CTU);
#include "clang/StaticAnalyzer/Core/Analyses.def"
} // end 'ento' namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index b0dda78a00a9..d605a6a667f6 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -15,9 +15,9 @@
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_ANALYSISMANAGER_H
#include "clang/Analysis/AnalysisDeclContext.h"
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
namespace clang {
@@ -32,7 +32,6 @@ class AnalysisManager : public BugReporterData {
AnalysisDeclContextManager AnaCtxMgr;
ASTContext &Ctx;
- DiagnosticsEngine &Diags;
const LangOptions &LangOpts;
PathDiagnosticConsumers PathConsumers;
@@ -45,7 +44,7 @@ class AnalysisManager : public BugReporterData {
public:
AnalyzerOptions &options;
- AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
+ AnalysisManager(ASTContext &ctx,
const PathDiagnosticConsumers &Consumers,
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr,
@@ -84,10 +83,6 @@ public:
return getASTContext().getSourceManager();
}
- DiagnosticsEngine &getDiagnostic() override {
- return Diags;
- }
-
const LangOptions &getLangOpts() const {
return LangOpts;
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index db84102983af..fc1cc9138826 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -347,7 +347,7 @@ public:
ProgramStateRef invalidateRegions(unsigned BlockCount,
ProgramStateRef Orig = nullptr) const;
- using FrameBindingTy = std::pair<Loc, SVal>;
+ using FrameBindingTy = std::pair<SVal, SVal>;
using BindingsTy = SmallVectorImpl<FrameBindingTy>;
/// Populates the given SmallVector with the bindings in the callee's stack
@@ -386,11 +386,12 @@ public:
/// during analysis if the call is inlined, but it may still be useful
/// in intermediate calculations even if the call isn't inlined.
/// May fail; returns null on failure.
- const StackFrameContext *getCalleeStackFrame() const;
+ const StackFrameContext *getCalleeStackFrame(unsigned BlockCount) const;
/// Returns memory location for a parameter variable within the callee stack
/// frame. May fail; returns null on failure.
- const VarRegion *getParameterLocation(unsigned Index) const;
+ const VarRegion *getParameterLocation(unsigned Index,
+ unsigned BlockCount) const;
/// Returns true if on the current path, the argument was constructed by
/// calling a C++ constructor over it. This is an internal detail of the
@@ -1063,8 +1064,19 @@ class CallDescription {
// e.g. "{a, b}" represent the qualified names, like "a::b".
std::vector<const char *> QualifiedName;
Optional<unsigned> RequiredArgs;
+ Optional<size_t> RequiredParams;
int Flags;
+ // A constructor helper.
+ static Optional<size_t> readRequiredParams(Optional<unsigned> RequiredArgs,
+ Optional<size_t> RequiredParams) {
+ if (RequiredParams)
+ return RequiredParams;
+ if (RequiredArgs)
+ return static_cast<size_t>(*RequiredArgs);
+ return None;
+ }
+
public:
/// Constructs a CallDescription object.
///
@@ -1077,14 +1089,17 @@ public:
/// call. Omit this parameter to match every occurrence of call with a given
/// name regardless the number of arguments.
CallDescription(int Flags, ArrayRef<const char *> QualifiedName,
- Optional<unsigned> RequiredArgs = None)
+ Optional<unsigned> RequiredArgs = None,
+ Optional<size_t> RequiredParams = None)
: QualifiedName(QualifiedName), RequiredArgs(RequiredArgs),
+ RequiredParams(readRequiredParams(RequiredArgs, RequiredParams)),
Flags(Flags) {}
/// Construct a CallDescription with default flags.
CallDescription(ArrayRef<const char *> QualifiedName,
- Optional<unsigned> RequiredArgs = None)
- : CallDescription(0, QualifiedName, RequiredArgs) {}
+ Optional<unsigned> RequiredArgs = None,
+ Optional<size_t> RequiredParams = None)
+ : CallDescription(0, QualifiedName, RequiredArgs, RequiredParams) {}
/// Get the name of the function that this object matches.
StringRef getFunctionName() const { return QualifiedName.back(); }
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index 981133e66977..7f4df0d88def 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -103,7 +103,7 @@ public:
return Eng.getBugReporter();
}
- SourceManager &getSourceManager() {
+ const SourceManager &getSourceManager() {
return getBugReporter().getSourceManager();
}
@@ -234,7 +234,7 @@ public:
}
/// A shorthand version of getNoteTag that doesn't require you to accept
- /// the BugReporterContext arguments when you don't need it.
+ /// the 'BugReporterContext' argument when you don't need it.
///
/// @param Cb Callback only with 'BugReport &' parameter.
/// @param IsPrunable Whether the note is prunable. It allows BugReporter
@@ -247,6 +247,19 @@ public:
IsPrunable);
}
+ /// A shorthand version of getNoteTag that doesn't require you to accept
+ /// the arguments when you don't need it.
+ ///
+ /// @param Cb Callback without parameters.
+ /// @param IsPrunable Whether the note is prunable. It allows BugReporter
+ /// to omit the note from the report if it would make the displayed
+ /// bug path significantly shorter.
+ const NoteTag *getNoteTag(std::function<std::string()> &&Cb,
+ bool IsPrunable = false) {
+ return getNoteTag([Cb](BugReporterContext &, BugReport &) { return Cb(); },
+ IsPrunable);
+ }
+
/// A shorthand version of getNoteTag that accepts a plain note.
///
/// @param Note The note.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicCastInfo.h b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicCastInfo.h
new file mode 100644
index 000000000000..f5a710c77a6a
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicCastInfo.h
@@ -0,0 +1,55 @@
+//===- DynamicCastInfo.h - Runtime cast information -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICCASTINFO_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICCASTINFO_H
+
+#include "clang/AST/Type.h"
+
+namespace clang {
+namespace ento {
+
+class DynamicCastInfo {
+public:
+ enum CastResult { Success, Failure };
+
+ DynamicCastInfo(QualType from, QualType to, CastResult resultKind)
+ : From(from), To(to), ResultKind(resultKind) {}
+
+ QualType from() const { return From; }
+ QualType to() const { return To; }
+
+ bool equals(QualType from, QualType to) const {
+ return From == from && To == to;
+ }
+
+ bool succeeds() const { return ResultKind == CastResult::Success; }
+ bool fails() const { return ResultKind == CastResult::Failure; }
+
+ bool operator==(const DynamicCastInfo &RHS) const {
+ return From == RHS.From && To == RHS.To;
+ }
+ bool operator<(const DynamicCastInfo &RHS) const {
+ return From < RHS.From && To < RHS.To;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.Add(From);
+ ID.Add(To);
+ ID.AddInteger(ResultKind);
+ }
+
+private:
+ QualType From, To;
+ CastResult ResultKind;
+};
+
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICCASTINFO_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h
new file mode 100644
index 000000000000..356401d77561
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h
@@ -0,0 +1,73 @@
+//===- DynamicType.h - Dynamic type related APIs ----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines APIs that track and query dynamic type information. This
+// information can be used to devirtualize calls during the symbolic execution
+// or do type checking.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPE_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPE_H
+
+#include "clang/AST/Type.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicCastInfo.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/Optional.h"
+#include <utility>
+
+namespace clang {
+namespace ento {
+
+/// Get dynamic type information for the region \p MR.
+DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR);
+
+/// Get raw dynamic type information for the region \p MR.
+const DynamicTypeInfo *getRawDynamicTypeInfo(ProgramStateRef State,
+ const MemRegion *MR);
+
+/// Get dynamic cast information from \p CastFromTy to \p CastToTy of \p MR.
+const DynamicCastInfo *getDynamicCastInfo(ProgramStateRef State,
+ const MemRegion *MR,
+ QualType CastFromTy,
+ QualType CastToTy);
+
+/// Set dynamic type information of the region; return the new state.
+ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR,
+ DynamicTypeInfo NewTy);
+
+/// Set dynamic type information of the region; return the new state.
+ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR,
+ QualType NewTy, bool CanBeSubClassed = true);
+
+/// Set dynamic type and cast information of the region; return the new state.
+ProgramStateRef setDynamicTypeAndCastInfo(ProgramStateRef State,
+ const MemRegion *MR,
+ QualType CastFromTy,
+ QualType CastToTy,
+ bool IsCastSucceeds);
+
+/// Removes the dead type informations from \p State.
+ProgramStateRef removeDeadTypes(ProgramStateRef State, SymbolReaper &SR);
+
+/// Removes the dead cast informations from \p State.
+ProgramStateRef removeDeadCasts(ProgramStateRef State, SymbolReaper &SR);
+
+void printDynamicTypeInfoJson(raw_ostream &Out, ProgramStateRef State,
+ const char *NL = "\n", unsigned int Space = 0,
+ bool IsDot = false);
+
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPE_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
index 9bb1e2137566..6262c4a1ce37 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h
@@ -1,10 +1,11 @@
-//== DynamicTypeInfo.h - Runtime type information ----------------*- C++ -*--=//
+//===- DynamicTypeInfo.h - Runtime type information -------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEINFO_H
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEINFO_H
@@ -16,36 +17,37 @@ namespace ento {
/// Stores the currently inferred strictest bound on the runtime type
/// of a region in a given state along the analysis path.
class DynamicTypeInfo {
-private:
- QualType T;
- bool CanBeASubClass;
-
public:
+ DynamicTypeInfo() : DynTy(QualType()) {}
- DynamicTypeInfo() : T(QualType()) {}
- DynamicTypeInfo(QualType WithType, bool CanBeSub = true)
- : T(WithType), CanBeASubClass(CanBeSub) {}
+ DynamicTypeInfo(QualType Ty, bool CanBeSub = true)
+ : DynTy(Ty), CanBeASubClass(CanBeSub) {}
+
+ /// Returns false if the type information is precise (the type 'DynTy' is
+ /// the only type in the lattice), true otherwise.
+ bool canBeASubClass() const { return CanBeASubClass; }
- /// Return false if no dynamic type info is available.
- bool isValid() const { return !T.isNull(); }
+ /// Returns true if the dynamic type info is available.
+ bool isValid() const { return !DynTy.isNull(); }
/// Returns the currently inferred upper bound on the runtime type.
- QualType getType() const { return T; }
+ QualType getType() const { return DynTy; }
- /// Returns false if the type information is precise (the type T is
- /// the only type in the lattice), true otherwise.
- bool canBeASubClass() const { return CanBeASubClass; }
+ bool operator==(const DynamicTypeInfo &RHS) const {
+ return DynTy == RHS.DynTy && CanBeASubClass == RHS.CanBeASubClass;
+ }
void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.Add(T);
- ID.AddInteger((unsigned)CanBeASubClass);
- }
- bool operator==(const DynamicTypeInfo &X) const {
- return T == X.T && CanBeASubClass == X.CanBeASubClass;
+ ID.Add(DynTy);
+ ID.AddBoolean(CanBeASubClass);
}
+
+private:
+ QualType DynTy;
+ bool CanBeASubClass;
};
-} // end ento
-} // end clang
+} // namespace ento
+} // namespace clang
-#endif
+#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEINFO_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h
deleted file mode 100644
index a84b24872061..000000000000
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h
+++ /dev/null
@@ -1,63 +0,0 @@
-//===- DynamicTypeMap.h - Dynamic type map ----------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file provides APIs for tracking dynamic type information.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H
-#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H
-
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "llvm/ADT/ImmutableMap.h"
-#include "clang/AST/Type.h"
-
-namespace clang {
-namespace ento {
-
-class MemRegion;
-
-/// The GDM component containing the dynamic type info. This is a map from a
-/// symbol to its most likely type.
-struct DynamicTypeMap {};
-
-using DynamicTypeMapTy = llvm::ImmutableMap<const MemRegion *, DynamicTypeInfo>;
-
-template <>
-struct ProgramStateTrait<DynamicTypeMap>
- : public ProgramStatePartialTrait<DynamicTypeMapTy> {
- static void *GDMIndex();
-};
-
-/// Get dynamic type information for a region.
-DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State,
- const MemRegion *Reg);
-
-/// Set dynamic type information of the region; return the new state.
-ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *Reg,
- DynamicTypeInfo NewTy);
-
-/// Set dynamic type information of the region; return the new state.
-inline ProgramStateRef setDynamicTypeInfo(ProgramStateRef State,
- const MemRegion *Reg, QualType NewTy,
- bool CanBeSubClassed = true) {
- return setDynamicTypeInfo(State, Reg,
- DynamicTypeInfo(NewTy, CanBeSubClassed));
-}
-
-void printDynamicTypeInfoJson(raw_ostream &Out, ProgramStateRef State,
- const char *NL = "\n", unsigned int Space = 0,
- bool IsDot = false);
-
-} // namespace ento
-} // namespace clang
-
-#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_DYNAMICTYPEMAP_H
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index 727d04cba278..e87772c04b9b 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -131,10 +131,12 @@ class ExplodedNode : public llvm::FoldingSetNode {
/// Succs - The successors of this node.
NodeGroup Succs;
+ int64_t Id;
+
public:
explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state,
- bool IsSink)
- : Location(loc), State(std::move(state)), Succs(IsSink) {
+ int64_t Id, bool IsSink)
+ : Location(loc), State(std::move(state)), Succs(IsSink), Id(Id) {
assert(isSink() == IsSink);
}
@@ -153,7 +155,11 @@ public:
CFG &getCFG() const { return *getLocationContext()->getCFG(); }
- ParentMap &getParentMap() const {return getLocationContext()->getParentMap();}
+ const CFGBlock *getCFGBlock() const;
+
+ const ParentMap &getParentMap() const {
+ return getLocationContext()->getParentMap();
+ }
template <typename T>
T &getAnalysis() const {
@@ -219,12 +225,20 @@ public:
// Iterators over successor and predecessor vertices.
using succ_iterator = ExplodedNode * const *;
+ using succ_range = llvm::iterator_range<succ_iterator>;
+
using const_succ_iterator = const ExplodedNode * const *;
+ using const_succ_range = llvm::iterator_range<const_succ_iterator>;
+
using pred_iterator = ExplodedNode * const *;
+ using pred_range = llvm::iterator_range<pred_iterator>;
+
using const_pred_iterator = const ExplodedNode * const *;
+ using const_pred_range = llvm::iterator_range<const_pred_iterator>;
pred_iterator pred_begin() { return Preds.begin(); }
pred_iterator pred_end() { return Preds.end(); }
+ pred_range preds() { return {Preds.begin(), Preds.end()}; }
const_pred_iterator pred_begin() const {
return const_cast<ExplodedNode*>(this)->pred_begin();
@@ -232,9 +246,11 @@ public:
const_pred_iterator pred_end() const {
return const_cast<ExplodedNode*>(this)->pred_end();
}
+ const_pred_range preds() const { return {Preds.begin(), Preds.end()}; }
succ_iterator succ_begin() { return Succs.begin(); }
succ_iterator succ_end() { return Succs.end(); }
+ succ_range succs() { return {Succs.begin(), Succs.end()}; }
const_succ_iterator succ_begin() const {
return const_cast<ExplodedNode*>(this)->succ_begin();
@@ -242,8 +258,9 @@ public:
const_succ_iterator succ_end() const {
return const_cast<ExplodedNode*>(this)->succ_end();
}
+ const_succ_range succs() const { return {Succs.begin(), Succs.end()}; }
- int64_t getID(ExplodedGraph *G) const;
+ int64_t getID() const { return Id; }
/// The node is trivial if it has only one successor, only one predecessor,
/// it's predecessor has only one successor,
@@ -252,6 +269,30 @@ public:
/// Trivial nodes may be skipped while printing exploded graph.
bool isTrivial() const;
+ /// If the node's program point corresponds to a statement, retrieve that
+ /// statement. Useful for figuring out where to put a warning or a note.
+ /// If the statement belongs to a body-farmed definition,
+ /// retrieve the call site for that definition.
+ const Stmt *getStmtForDiagnostics() const;
+
+ /// Find the next statement that was executed on this node's execution path.
+ /// Useful for explaining control flow that follows the current node.
+ /// If the statement belongs to a body-farmed definition, retrieve the
+ /// call site for that definition.
+ const Stmt *getNextStmtForDiagnostics() const;
+
+ /// Find the statement that was executed immediately before this node.
+ /// Useful when the node corresponds to a CFG block entrance.
+ /// If the statement belongs to a body-farmed definition, retrieve the
+ /// call site for that definition.
+ const Stmt *getPreviousStmtForDiagnostics() const;
+
+ /// Find the statement that was executed at or immediately before this node.
+ /// Useful when any nearby statement will do.
+ /// If the statement belongs to a body-farmed definition, retrieve the
+ /// call site for that definition.
+ const Stmt *getCurrentOrPreviousStmtForDiagnostics() const;
+
private:
void replaceSuccessor(ExplodedNode *node) { Succs.replaceNode(node); }
void replacePredecessor(ExplodedNode *node) { Preds.replaceNode(node); }
@@ -285,7 +326,7 @@ protected:
BumpVectorContext BVC;
/// NumNodes - The number of nodes in the graph.
- unsigned NumNodes = 0;
+ int64_t NumNodes = 0;
/// A list of recently allocated nodes that can potentially be recycled.
NodeVector ChangedNodes;
@@ -319,10 +360,11 @@ public:
/// ExplodedGraph for further processing.
ExplodedNode *createUncachedNode(const ProgramPoint &L,
ProgramStateRef State,
+ int64_t Id,
bool IsSink = false);
std::unique_ptr<ExplodedGraph> MakeEmptyGraph() const {
- return llvm::make_unique<ExplodedGraph>();
+ return std::make_unique<ExplodedGraph>();
}
/// addRoot - Add an untyped node to the set of roots.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 2629d7121de4..2d0967616ff2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -145,9 +145,9 @@ private:
ObjCNoReturn ObjCNoRet;
/// The BugReporter associated with this engine. It is important that
- /// this object be placed at the very end of member variables so that its
- /// destructor is called before the rest of the ExprEngine is destroyed.
- GRBugReporter BR;
+ /// this object be placed at the very end of member variables so that its
+ /// destructor is called before the rest of the ExprEngine is destroyed.
+ PathSensitiveBugReporter BR;
/// The functions which have been analyzed through inlining. This is owned by
/// AnalysisConsumer. It can be null.
@@ -530,7 +530,7 @@ public:
void VisitCXXDestructor(QualType ObjectType, const MemRegion *Dest,
const Stmt *S, bool IsBaseDtor,
ExplodedNode *Pred, ExplodedNodeSet &Dst,
- const EvalCallOptions &Options);
+ EvalCallOptions &Options);
void VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
ExplodedNode *Pred,
@@ -666,7 +666,7 @@ public:
const LocationContext *LCtx,
ProgramStateRef State);
- /// Evaluate a call, running pre- and post-call checks and allowing checkers
+ /// Evaluate a call, running pre- and post-call checkers and allowing checkers
/// to be responsible for handling the evaluation of the call itself.
void evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
const CallEvent &Call);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 071e35085a5f..71cbbe28fc25 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -169,6 +169,7 @@ public:
Kind getKind() const { return kind; }
template<typename RegionTy> const RegionTy* getAs() const;
+ template<typename RegionTy> const RegionTy* castAs() const;
virtual bool isBoundable() const { return false; }
@@ -1231,6 +1232,11 @@ const RegionTy* MemRegion::getAs() const {
return nullptr;
}
+template<typename RegionTy>
+const RegionTy* MemRegion::castAs() const {
+ return cast<RegionTy>(this);
+}
+
//===----------------------------------------------------------------------===//
// MemRegionManager - Factory object for creating regions.
//===----------------------------------------------------------------------===//
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index d38058f9af56..07920790c80a 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -507,6 +507,10 @@ public:
return *svalBuilder;
}
+ const SValBuilder &getSValBuilder() const {
+ return *svalBuilder;
+ }
+
SymbolManager &getSymbolManager() {
return svalBuilder->getSymbolManager();
}
diff --git a/include/clang/Tooling/ASTDiff/ASTDiff.h b/include/clang/Tooling/ASTDiff/ASTDiff.h
index d6cbc09dcede..c1cc124e1e9f 100644
--- a/include/clang/Tooling/ASTDiff/ASTDiff.h
+++ b/include/clang/Tooling/ASTDiff/ASTDiff.h
@@ -71,7 +71,7 @@ public:
/// Constructs a tree from any AST node.
template <class T>
SyntaxTree(T *Node, ASTContext &AST)
- : TreeImpl(llvm::make_unique<Impl>(this, Node, AST)) {}
+ : TreeImpl(std::make_unique<Impl>(this, Node, AST)) {}
SyntaxTree(SyntaxTree &&Other) = default;
~SyntaxTree();
diff --git a/include/clang/Tooling/AllTUsExecution.h b/include/clang/Tooling/AllTUsExecution.h
index e670f54234a6..1e618b5ba2f0 100644
--- a/include/clang/Tooling/AllTUsExecution.h
+++ b/include/clang/Tooling/AllTUsExecution.h
@@ -44,8 +44,6 @@ public:
StringRef getExecutorName() const override { return ExecutorName; }
- bool isSingleProcess() const override { return true; }
-
using ToolExecutor::execute;
llvm::Error
@@ -71,6 +69,7 @@ private:
unsigned ThreadCount;
};
+extern llvm::cl::opt<unsigned> ExecutorConcurrency;
extern llvm::cl::opt<std::string> Filter;
} // end namespace tooling
diff --git a/include/clang/Tooling/ArgumentsAdjusters.h b/include/clang/Tooling/ArgumentsAdjusters.h
index bf0886034324..c48a8725aae9 100644
--- a/include/clang/Tooling/ArgumentsAdjusters.h
+++ b/include/clang/Tooling/ArgumentsAdjusters.h
@@ -43,6 +43,10 @@ ArgumentsAdjuster getClangSyntaxOnlyAdjuster();
/// arguments.
ArgumentsAdjuster getClangStripOutputAdjuster();
+/// Gets an argument adjuster which removes command line arguments related to
+/// diagnostic serialization.
+ArgumentsAdjuster getClangStripSerializeDiagnosticAdjuster();
+
/// Gets an argument adjuster which removes dependency-file
/// related command line arguments.
ArgumentsAdjuster getClangStripDependencyFileAdjuster();
diff --git a/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h b/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h
new file mode 100644
index 000000000000..7d0881343478
--- /dev/null
+++ b/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h
@@ -0,0 +1,188 @@
+//===- DependencyScanningFilesystem.h - clang-scan-deps fs ===---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_FILESYSTEM_H
+#define LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_FILESYSTEM_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Lex/PreprocessorExcludedConditionalDirectiveSkipMapping.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include <mutex>
+
+namespace clang {
+namespace tooling {
+namespace dependencies {
+
+/// An in-memory representation of a file system entity that is of interest to
+/// the dependency scanning filesystem.
+///
+/// It represents one of the following:
+/// - an opened source file with minimized contents and a stat value.
+/// - an opened source file with original contents and a stat value.
+/// - a directory entry with its stat value.
+/// - an error value to represent a file system error.
+/// - a placeholder with an invalid stat indicating a not yet initialized entry.
+class CachedFileSystemEntry {
+public:
+ /// Default constructor creates an entry with an invalid stat.
+ CachedFileSystemEntry() : MaybeStat(llvm::vfs::Status()) {}
+
+ CachedFileSystemEntry(std::error_code Error) : MaybeStat(std::move(Error)) {}
+
+ /// Create an entry that represents an opened source file with minimized or
+ /// original contents.
+ ///
+ /// The filesystem opens the file even for `stat` calls open to avoid the
+ /// issues with stat + open of minimized files that might lead to a
+ /// mismatching size of the file. If file is not minimized, the full file is
+ /// read and copied into memory to ensure that it's not memory mapped to avoid
+ /// running out of file descriptors.
+ static CachedFileSystemEntry createFileEntry(StringRef Filename,
+ llvm::vfs::FileSystem &FS,
+ bool Minimize = true);
+
+ /// Create an entry that represents a directory on the filesystem.
+ static CachedFileSystemEntry createDirectoryEntry(llvm::vfs::Status &&Stat);
+
+ /// \returns True if the entry is valid.
+ bool isValid() const { return !MaybeStat || MaybeStat->isStatusKnown(); }
+
+ /// \returns True if the current entry points to a directory.
+ bool isDirectory() const { return MaybeStat && MaybeStat->isDirectory(); }
+
+ /// \returns The error or the file's contents.
+ llvm::ErrorOr<StringRef> getContents() const {
+ if (!MaybeStat)
+ return MaybeStat.getError();
+ assert(!MaybeStat->isDirectory() && "not a file");
+ assert(isValid() && "not initialized");
+ return StringRef(Contents);
+ }
+
+ /// \returns The error or the status of the entry.
+ llvm::ErrorOr<llvm::vfs::Status> getStatus() const {
+ assert(isValid() && "not initialized");
+ return MaybeStat;
+ }
+
+ /// \returns the name of the file.
+ StringRef getName() const {
+ assert(isValid() && "not initialized");
+ return MaybeStat->getName();
+ }
+
+ /// Return the mapping between location -> distance that is used to speed up
+ /// the block skipping in the preprocessor.
+ const PreprocessorSkippedRangeMapping &getPPSkippedRangeMapping() const {
+ return PPSkippedRangeMapping;
+ }
+
+ CachedFileSystemEntry(CachedFileSystemEntry &&) = default;
+ CachedFileSystemEntry &operator=(CachedFileSystemEntry &&) = default;
+
+ CachedFileSystemEntry(const CachedFileSystemEntry &) = delete;
+ CachedFileSystemEntry &operator=(const CachedFileSystemEntry &) = delete;
+
+private:
+ llvm::ErrorOr<llvm::vfs::Status> MaybeStat;
+ // Store the contents in a small string to allow a
+ // move from the small string for the minimized contents.
+ // Note: small size of 1 allows us to store an empty string with an implicit
+ // null terminator without any allocations.
+ llvm::SmallString<1> Contents;
+ PreprocessorSkippedRangeMapping PPSkippedRangeMapping;
+};
+
+/// This class is a shared cache, that caches the 'stat' and 'open' calls to the
+/// underlying real file system.
+///
+/// It is sharded based on the hash of the key to reduce the lock contention for
+/// the worker threads.
+class DependencyScanningFilesystemSharedCache {
+public:
+ struct SharedFileSystemEntry {
+ std::mutex ValueLock;
+ CachedFileSystemEntry Value;
+ };
+
+ DependencyScanningFilesystemSharedCache();
+
+ /// Returns a cache entry for the corresponding key.
+ ///
+ /// A new cache entry is created if the key is not in the cache. This is a
+ /// thread safe call.
+ SharedFileSystemEntry &get(StringRef Key);
+
+private:
+ struct CacheShard {
+ std::mutex CacheLock;
+ llvm::StringMap<SharedFileSystemEntry, llvm::BumpPtrAllocator> Cache;
+ };
+ std::unique_ptr<CacheShard[]> CacheShards;
+ unsigned NumShards;
+};
+
+/// A virtual file system optimized for the dependency discovery.
+///
+/// It is primarily designed to work with source files whose contents was was
+/// preprocessed to remove any tokens that are unlikely to affect the dependency
+/// computation.
+///
+/// This is not a thread safe VFS. A single instance is meant to be used only in
+/// one thread. Multiple instances are allowed to service multiple threads
+/// running in parallel.
+class DependencyScanningWorkerFilesystem : public llvm::vfs::ProxyFileSystem {
+public:
+ DependencyScanningWorkerFilesystem(
+ DependencyScanningFilesystemSharedCache &SharedCache,
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
+ ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings)
+ : ProxyFileSystem(std::move(FS)), SharedCache(SharedCache),
+ PPSkipMappings(PPSkipMappings) {}
+
+ llvm::ErrorOr<llvm::vfs::Status> status(const Twine &Path) override;
+ llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
+ openFileForRead(const Twine &Path) override;
+
+ /// The set of files that should not be minimized.
+ llvm::StringSet<> IgnoredFiles;
+
+private:
+ void setCachedEntry(StringRef Filename, const CachedFileSystemEntry *Entry) {
+ bool IsInserted = Cache.try_emplace(Filename, Entry).second;
+ (void)IsInserted;
+ assert(IsInserted && "local cache is updated more than once");
+ }
+
+ const CachedFileSystemEntry *getCachedEntry(StringRef Filename) {
+ auto It = Cache.find(Filename);
+ return It == Cache.end() ? nullptr : It->getValue();
+ }
+
+ llvm::ErrorOr<const CachedFileSystemEntry *>
+ getOrCreateFileSystemEntry(const StringRef Filename);
+
+ DependencyScanningFilesystemSharedCache &SharedCache;
+ /// The local cache is used by the worker thread to cache file system queries
+ /// locally instead of querying the global cache every time.
+ llvm::StringMap<const CachedFileSystemEntry *, llvm::BumpPtrAllocator> Cache;
+ /// The optional mapping structure which records information about the
+ /// excluded conditional directive skip mappings that are used by the
+ /// currently active preprocessor.
+ ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings;
+};
+
+} // end namespace dependencies
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_FILESYSTEM_H
diff --git a/include/clang/Tooling/DependencyScanning/DependencyScanningService.h b/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
new file mode 100644
index 000000000000..fd8ed80b143c
--- /dev/null
+++ b/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
@@ -0,0 +1,65 @@
+//===- DependencyScanningService.h - clang-scan-deps service ===-*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_SERVICE_H
+#define LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_SERVICE_H
+
+#include "clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h"
+
+namespace clang {
+namespace tooling {
+namespace dependencies {
+
+/// The mode in which the dependency scanner will operate to find the
+/// dependencies.
+enum class ScanningMode {
+ /// This mode is used to compute the dependencies by running the preprocessor
+ /// over
+ /// the unmodified source files.
+ CanonicalPreprocessing,
+
+ /// This mode is used to compute the dependencies by running the preprocessor
+ /// over
+ /// the source files that have been minimized to contents that might affect
+ /// the dependencies.
+ MinimizedSourcePreprocessing
+};
+
+/// The dependency scanning service contains the shared state that is used by
+/// the invidual dependency scanning workers.
+class DependencyScanningService {
+public:
+ DependencyScanningService(ScanningMode Mode, bool ReuseFileManager = true,
+ bool SkipExcludedPPRanges = true);
+
+ ScanningMode getMode() const { return Mode; }
+
+ bool canReuseFileManager() const { return ReuseFileManager; }
+
+ bool canSkipExcludedPPRanges() const { return SkipExcludedPPRanges; }
+
+ DependencyScanningFilesystemSharedCache &getSharedCache() {
+ return SharedCache;
+ }
+
+private:
+ const ScanningMode Mode;
+ const bool ReuseFileManager;
+ /// Set to true to use the preprocessor optimization that skips excluded PP
+ /// ranges by bumping the buffer pointer in the lexer instead of lexing the
+ /// tokens in the range until reaching the corresponding directive.
+ const bool SkipExcludedPPRanges;
+ /// The global file system cache.
+ DependencyScanningFilesystemSharedCache SharedCache;
+};
+
+} // end namespace dependencies
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_SERVICE_H
diff --git a/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h b/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
new file mode 100644
index 000000000000..0c9efccb1d8b
--- /dev/null
+++ b/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
@@ -0,0 +1,48 @@
+//===- DependencyScanningTool.h - clang-scan-deps service ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_TOOL_H
+#define LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_TOOL_H
+
+#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
+#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
+#include "clang/Tooling/JSONCompilationDatabase.h"
+#include <string>
+
+namespace clang{
+namespace tooling{
+namespace dependencies{
+
+/// The high-level implementation of the dependency discovery tool that runs on
+/// an individual worker thread.
+class DependencyScanningTool {
+public:
+ /// Construct a dependency scanning tool.
+ ///
+ /// \param Compilations The reference to the compilation database that's
+ /// used by the clang tool.
+ DependencyScanningTool(DependencyScanningService &Service, const clang::tooling::CompilationDatabase &Compilations);
+
+ /// Print out the dependency information into a string using the dependency
+ /// file format that is specified in the options (-MD is the default) and
+ /// return it.
+ ///
+ /// \returns A \c StringError with the diagnostic output if clang errors
+ /// occurred, dependency file contents otherwise.
+ llvm::Expected<std::string> getDependencyFile(const std::string &Input, StringRef CWD);
+
+private:
+ DependencyScanningWorker Worker;
+ const tooling::CompilationDatabase &Compilations;
+};
+
+} // end namespace dependencies
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_TOOL_H
diff --git a/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h b/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
index 3ea261a30d0f..45c9fb4f029d 100644
--- a/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
+++ b/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
@@ -10,17 +10,35 @@
#define LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_WORKER_H
#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/LLVM.h"
#include "clang/Frontend/PCHContainerOperations.h"
+#include "clang/Lex/PreprocessorExcludedConditionalDirectiveSkipMapping.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include <string>
namespace clang {
+
+class DependencyOutputOptions;
+
namespace tooling {
namespace dependencies {
+class DependencyScanningService;
+class DependencyScanningWorkerFilesystem;
+
+class DependencyConsumer {
+public:
+ virtual ~DependencyConsumer() {}
+
+ virtual void handleFileDependency(const DependencyOutputOptions &Opts,
+ StringRef Filename) = 0;
+
+ // FIXME: Add support for reporting modular dependencies.
+};
+
/// An individual dependency scanning worker that is able to run on its own
/// thread.
///
@@ -29,26 +47,32 @@ namespace dependencies {
/// using the regular processing run.
class DependencyScanningWorker {
public:
- DependencyScanningWorker();
+ DependencyScanningWorker(DependencyScanningService &Service);
- /// Print out the dependency information into a string using the dependency
- /// file format that is specified in the options (-MD is the default) and
- /// return it.
+ /// Run the dependency scanning tool for a given clang driver invocation (as
+ /// specified for the given Input in the CDB), and report the discovered
+ /// dependencies to the provided consumer.
///
/// \returns A \c StringError with the diagnostic output if clang errors
- /// occurred, dependency file contents otherwise.
- llvm::Expected<std::string> getDependencyFile(const std::string &Input,
- StringRef WorkingDirectory,
- const CompilationDatabase &CDB);
+ /// occurred, success otherwise.
+ llvm::Error computeDependencies(const std::string &Input,
+ StringRef WorkingDirectory,
+ const CompilationDatabase &CDB,
+ DependencyConsumer &Consumer);
private:
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
std::shared_ptr<PCHContainerOperations> PCHContainerOps;
+ std::unique_ptr<ExcludedPreprocessorDirectiveSkipMapping> PPSkipMappings;
+ llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> RealFS;
/// The file system that is used by each worker when scanning for
/// dependencies. This filesystem persists accross multiple compiler
/// invocations.
- llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> WorkerFS;
+ llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;
+ /// The file manager that is reused accross multiple invocations by this
+ /// worker. If null, the file manager will not be reused.
+ llvm::IntrusiveRefCntPtr<FileManager> Files;
};
} // end namespace dependencies
diff --git a/include/clang/Tooling/Execution.h b/include/clang/Tooling/Execution.h
index 74f0df5a5b91..ca6f22c5da3b 100644
--- a/include/clang/Tooling/Execution.h
+++ b/include/clang/Tooling/Execution.h
@@ -115,13 +115,6 @@ public:
/// Returns the name of a specific executor.
virtual StringRef getExecutorName() const = 0;
- /// Should return true iff executor runs all actions in a single process.
- /// Clients can use this signal to find out if they can collect results
- /// in-memory (e.g. to avoid serialization costs of using ToolResults).
- /// The single-process executors can still run multiple threads, but all
- /// executions are guaranteed to share the same memory.
- virtual bool isSingleProcess() const = 0;
-
/// Executes each action with a corresponding arguments adjuster.
virtual llvm::Error
execute(llvm::ArrayRef<
diff --git a/include/clang/Tooling/Inclusions/HeaderIncludes.h b/include/clang/Tooling/Inclusions/HeaderIncludes.h
index ec6f0ea45ffe..6e6d6d8fb024 100644
--- a/include/clang/Tooling/Inclusions/HeaderIncludes.h
+++ b/include/clang/Tooling/Inclusions/HeaderIncludes.h
@@ -32,6 +32,7 @@ public:
/// 0. Otherwise, returns the priority of the matching category or INT_MAX.
/// NOTE: this API is not thread-safe!
int getIncludePriority(StringRef IncludeName, bool CheckMainHeader) const;
+ int getSortIncludePriority(StringRef IncludeName, bool CheckMainHeader) const;
private:
bool isMainHeader(StringRef IncludeName) const;
diff --git a/include/clang/Tooling/Inclusions/IncludeStyle.h b/include/clang/Tooling/Inclusions/IncludeStyle.h
index a0f236e6fc46..266763a5b1bd 100644
--- a/include/clang/Tooling/Inclusions/IncludeStyle.h
+++ b/include/clang/Tooling/Inclusions/IncludeStyle.h
@@ -58,6 +58,8 @@ struct IncludeStyle {
std::string Regex;
/// The priority to assign to this category.
int Priority;
+ /// The custom priority to sort before grouping.
+ int SortPriority;
bool operator==(const IncludeCategory &Other) const {
return Regex == Other.Regex && Priority == Other.Priority;
}
diff --git a/lib/Tooling/Refactoring/Extract/SourceExtraction.h b/include/clang/Tooling/Refactoring/Extract/SourceExtraction.h
index 545eb6c1a11c..034a0aaaf6db 100644..100755
--- a/lib/Tooling/Refactoring/Extract/SourceExtraction.h
+++ b/include/clang/Tooling/Refactoring/Extract/SourceExtraction.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_LIB_TOOLING_REFACTORING_EXTRACT_SOURCE_EXTRACTION_H
-#define LLVM_CLANG_LIB_TOOLING_REFACTORING_EXTRACT_SOURCE_EXTRACTION_H
+#ifndef LLVM_CLANG_TOOLING_REFACTORING_EXTRACT_SOURCE_EXTRACTION_H
+#define LLVM_CLANG_TOOLING_REFACTORING_EXTRACT_SOURCE_EXTRACTION_H
#include "clang/Basic/LLVM.h"
@@ -48,4 +48,4 @@ private:
} // end namespace tooling
} // end namespace clang
-#endif // LLVM_CLANG_LIB_TOOLING_REFACTORING_EXTRACT_SOURCE_EXTRACTION_H
+#endif //LLVM_CLANG_TOOLING_REFACTORING_EXTRACT_SOURCE_EXTRACTION_H
diff --git a/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h b/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h
index 41a448f035a4..c0f995d85c14 100644
--- a/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h
+++ b/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h
@@ -98,7 +98,17 @@ public:
TypeBeginLoc, TypeEndLoc))
return false;
}
- return visit(Loc.getType()->getAsCXXRecordDecl(), TypeBeginLoc, TypeEndLoc);
+ if (const Type *TP = Loc.getTypePtr()) {
+ if (TP->getTypeClass() == clang::Type::Record)
+ return visit(TP->getAsCXXRecordDecl(), TypeBeginLoc, TypeEndLoc);
+ }
+ return true;
+ }
+
+ bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
+ const SourceLocation TypeEndLoc =
+ Lexer::getLocForEndOfToken(TL.getBeginLoc(), 0, SM, LangOpts);
+ return visit(TL.getTypedefNameDecl(), TL.getBeginLoc(), TypeEndLoc);
}
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
@@ -122,8 +132,7 @@ private:
ND, SourceRange(BeginLoc, EndLoc));
}
bool visit(const NamedDecl *ND, SourceLocation Loc) {
- return visit(ND, Loc,
- Loc.getLocWithOffset(ND->getNameAsString().length() - 1));
+ return visit(ND, Loc, Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts));
}
};
diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h b/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h
index cc6ae83202f1..fb373fcf5029 100644
--- a/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h
+++ b/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h
@@ -47,7 +47,7 @@ template <typename RuleType, typename... RequirementTypes, size_t... Is>
void invokeRuleAfterValidatingRequirements(
RefactoringResultConsumer &Consumer, RefactoringRuleContext &Context,
const std::tuple<RequirementTypes...> &Requirements,
- llvm::index_sequence<Is...>) {
+ std::index_sequence<Is...>) {
// Check if the requirements we're interested in can be evaluated.
auto Values =
std::make_tuple(std::get<Is>(Requirements).evaluate(Context)...);
@@ -87,7 +87,7 @@ template <typename... RequirementTypes, size_t... Is>
void visitRefactoringOptions(
RefactoringOptionVisitor &Visitor,
const std::tuple<RequirementTypes...> &Requirements,
- llvm::index_sequence<Is...>) {
+ std::index_sequence<Is...>) {
visitRefactoringOptionsImpl(Visitor, std::get<Is>(Requirements)...);
}
@@ -131,7 +131,7 @@ createRefactoringActionRule(const RequirementTypes &... Requirements) {
RefactoringRuleContext &Context) override {
internal::invokeRuleAfterValidatingRequirements<RuleType>(
Consumer, Context, Requirements,
- llvm::index_sequence_for<RequirementTypes...>());
+ std::index_sequence_for<RequirementTypes...>());
}
bool hasSelectionRequirement() override {
@@ -142,13 +142,13 @@ createRefactoringActionRule(const RequirementTypes &... Requirements) {
void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) override {
internal::visitRefactoringOptions(
Visitor, Requirements,
- llvm::index_sequence_for<RequirementTypes...>());
+ std::index_sequence_for<RequirementTypes...>());
}
private:
std::tuple<RequirementTypes...> Requirements;
};
- return llvm::make_unique<Rule>(std::make_tuple(Requirements...));
+ return std::make_unique<Rule>(std::make_tuple(Requirements...));
}
} // end namespace tooling
diff --git a/include/clang/Tooling/StandaloneExecution.h b/include/clang/Tooling/StandaloneExecution.h
index 5fbc1e479c59..8db6229acf7f 100644
--- a/include/clang/Tooling/StandaloneExecution.h
+++ b/include/clang/Tooling/StandaloneExecution.h
@@ -52,8 +52,6 @@ public:
StringRef getExecutorName() const override { return ExecutorName; }
- bool isSingleProcess() const override { return true; }
-
using ToolExecutor::execute;
llvm::Error
diff --git a/include/clang/Tooling/Syntax/Tokens.h b/include/clang/Tooling/Syntax/Tokens.h
index 4640ccb2d30a..301432d3888b 100644
--- a/include/clang/Tooling/Syntax/Tokens.h
+++ b/include/clang/Tooling/Syntax/Tokens.h
@@ -236,6 +236,16 @@ public:
/// #pragma, etc.
llvm::ArrayRef<syntax::Token> spelledTokens(FileID FID) const;
+ /// Get all tokens that expand a macro in \p FID. For the following input
+ /// #define FOO B
+ /// #define FOO2(X) int X
+ /// FOO2(XY)
+ /// int B;
+ /// FOO;
+ /// macroExpansions() returns {"FOO2", "FOO"} (from line 3 and 5
+ /// respecitvely).
+ std::vector<const syntax::Token *> macroExpansions(FileID FID) const;
+
const SourceManager &sourceManager() const { return *SourceMgr; }
std::string dumpForTests() const;
diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h
index 83fe43ac59e0..19421f0a39f3 100644
--- a/include/clang/Tooling/Tooling.h
+++ b/include/clang/Tooling/Tooling.h
@@ -99,9 +99,7 @@ public:
DiagnosticConsumer *DiagConsumer) override;
/// Returns a new clang::FrontendAction.
- ///
- /// The caller takes ownership of the returned action.
- virtual FrontendAction *create() = 0;
+ virtual std::unique_ptr<FrontendAction> create() = 0;
};
/// Returns a new FrontendActionFactory for a given type.
@@ -156,7 +154,7 @@ inline std::unique_ptr<FrontendActionFactory> newFrontendActionFactory(
/// clang modules.
///
/// \return - True if 'ToolAction' was successfully executed.
-bool runToolOnCode(FrontendAction *ToolAction, const Twine &Code,
+bool runToolOnCode(std::unique_ptr<FrontendAction> ToolAction, const Twine &Code,
const Twine &FileName = "input.cc",
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
std::make_shared<PCHContainerOperations>());
@@ -179,7 +177,7 @@ using FileContentMappings = std::vector<std::pair<std::string, std::string>>;
///
/// \return - True if 'ToolAction' was successfully executed.
bool runToolOnCodeWithArgs(
- FrontendAction *ToolAction, const Twine &Code,
+ std::unique_ptr<FrontendAction> ToolAction, const Twine &Code,
const std::vector<std::string> &Args, const Twine &FileName = "input.cc",
const Twine &ToolName = "clang-tool",
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
@@ -188,7 +186,7 @@ bool runToolOnCodeWithArgs(
// Similar to the overload except this takes a VFS.
bool runToolOnCodeWithArgs(
- FrontendAction *ToolAction, const Twine &Code,
+ std::unique_ptr<FrontendAction> ToolAction, const Twine &Code,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
const std::vector<std::string> &Args, const Twine &FileName = "input.cc",
const Twine &ToolName = "clang-tool",
@@ -237,13 +235,13 @@ public:
/// uses its binary name (CommandLine[0]) to locate its builtin headers.
/// Callers have to ensure that they are installed in a compatible location
/// (see clang driver implementation) or mapped in via mapVirtualFile.
- /// \param FAction The action to be executed. Class takes ownership.
+ /// \param FAction The action to be executed.
/// \param Files The FileManager used for the execution. Class does not take
/// ownership.
/// \param PCHContainerOps The PCHContainerOperations for loading and creating
/// clang modules.
- ToolInvocation(std::vector<std::string> CommandLine, FrontendAction *FAction,
- FileManager *Files,
+ ToolInvocation(std::vector<std::string> CommandLine,
+ std::unique_ptr<FrontendAction> FAction, FileManager *Files,
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
std::make_shared<PCHContainerOperations>());
@@ -314,12 +312,15 @@ public:
/// clang modules.
/// \param BaseFS VFS used for all underlying file accesses when running the
/// tool.
+ /// \param Files The file manager to use for underlying file operations when
+ /// running the tool.
ClangTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths,
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
std::make_shared<PCHContainerOperations>(),
IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS =
- llvm::vfs::getRealFileSystem());
+ llvm::vfs::getRealFileSystem(),
+ IntrusiveRefCntPtr<FileManager> Files = nullptr);
~ClangTool();
@@ -397,7 +398,9 @@ template <typename T>
std::unique_ptr<FrontendActionFactory> newFrontendActionFactory() {
class SimpleFrontendActionFactory : public FrontendActionFactory {
public:
- FrontendAction *create() override { return new T; }
+ std::unique_ptr<FrontendAction> create() override {
+ return std::make_unique<T>();
+ }
};
return std::unique_ptr<FrontendActionFactory>(
@@ -413,8 +416,9 @@ inline std::unique_ptr<FrontendActionFactory> newFrontendActionFactory(
SourceFileCallbacks *Callbacks)
: ConsumerFactory(ConsumerFactory), Callbacks(Callbacks) {}
- FrontendAction *create() override {
- return new ConsumerFactoryAdaptor(ConsumerFactory, Callbacks);
+ std::unique_ptr<FrontendAction> create() override {
+ return std::make_unique<ConsumerFactoryAdaptor>(ConsumerFactory,
+ Callbacks);
}
private:
diff --git a/include/clang/Tooling/Transformer/MatchConsumer.h b/include/clang/Tooling/Transformer/MatchConsumer.h
new file mode 100644
index 000000000000..0a1dbe13ea1e
--- /dev/null
+++ b/include/clang/Tooling/Transformer/MatchConsumer.h
@@ -0,0 +1,62 @@
+//===--- MatchConsumer.h - MatchConsumer abstraction ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file This file defines the *MatchConsumer* abstraction: a computation over
+/// match results, specifically the `ast_matchers::MatchFinder::MatchResult`
+/// class.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_TRANSFORMER_MATCH_CONSUMER_H_
+#define LLVM_CLANG_TOOLING_TRANSFORMER_MATCH_CONSUMER_H_
+
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace transformer {
+/// A failable computation over nodes bound by AST matchers.
+///
+/// The computation should report any errors though its return value (rather
+/// than terminating the program) to enable usage in interactive scenarios like
+/// clang-query.
+///
+/// This is a central abstraction of the Transformer framework.
+template <typename T>
+using MatchConsumer =
+ std::function<Expected<T>(const ast_matchers::MatchFinder::MatchResult &)>;
+
+/// Creates an error that signals that a `MatchConsumer` expected a certain node
+/// to be bound by AST matchers, but it was not actually bound.
+inline llvm::Error notBoundError(llvm::StringRef Id) {
+ return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
+ "Id not bound: " + Id);
+}
+
+/// Chooses between the two consumers, based on whether \p ID is bound in the
+/// match.
+template <typename T>
+MatchConsumer<T> ifBound(std::string ID, MatchConsumer<T> TrueC,
+ MatchConsumer<T> FalseC) {
+ return [=](const ast_matchers::MatchFinder::MatchResult &Result) {
+ auto &Map = Result.Nodes.getMap();
+ return (Map.find(ID) != Map.end() ? TrueC : FalseC)(Result);
+ };
+}
+} // namespace transformer
+
+namespace tooling {
+// DEPRECATED: Temporary alias supporting client migration to the `transformer`
+// namespace.
+using transformer::ifBound;
+} // namespace tooling
+} // namespace clang
+#endif // LLVM_CLANG_TOOLING_TRANSFORMER_MATCH_CONSUMER_H_
diff --git a/include/clang/Tooling/Refactoring/RangeSelector.h b/include/clang/Tooling/Transformer/RangeSelector.h
index b117e4d82ad4..9f556d206321 100644
--- a/include/clang/Tooling/Refactoring/RangeSelector.h
+++ b/include/clang/Tooling/Transformer/RangeSelector.h
@@ -17,14 +17,14 @@
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Transformer/MatchConsumer.h"
#include "llvm/Support/Error.h"
#include <functional>
#include <string>
namespace clang {
-namespace tooling {
-using RangeSelector = std::function<Expected<CharSourceRange>(
- const ast_matchers::MatchFinder::MatchResult &)>;
+namespace transformer {
+using RangeSelector = MatchConsumer<CharSourceRange>;
inline RangeSelector charRange(CharSourceRange R) {
return [R](const ast_matchers::MatchFinder::MatchResult &)
@@ -79,10 +79,34 @@ RangeSelector statements(std::string ID);
// (all source between the braces).
RangeSelector initListElements(std::string ID);
+/// Given an \IfStmt (bound to \p ID), selects the range of the else branch,
+/// starting from the \c else keyword.
+RangeSelector elseBranch(std::string ID);
+
/// Selects the range from which `S` was expanded (possibly along with other
/// source), if `S` is an expansion, and `S` itself, otherwise. Corresponds to
/// `SourceManager::getExpansionRange`.
RangeSelector expansion(RangeSelector S);
+} // namespace transformer
+
+namespace tooling {
+// DEPRECATED: These are temporary aliases supporting client migration to the
+// `transformer` namespace.
+using RangeSelector = transformer::RangeSelector;
+
+using transformer::after;
+using transformer::before;
+using transformer::callArgs;
+using transformer::charRange;
+using transformer::elseBranch;
+using transformer::expansion;
+using transformer::initListElements;
+using transformer::member;
+using transformer::name;
+using transformer::node;
+using transformer::range;
+using transformer::statement;
+using transformer::statements;
} // namespace tooling
} // namespace clang
diff --git a/include/clang/Tooling/Refactoring/Transformer.h b/include/clang/Tooling/Transformer/RewriteRule.h
index 6d9c5a37cc18..6e99151c1c7f 100644
--- a/include/clang/Tooling/Refactoring/Transformer.h
+++ b/include/clang/Tooling/Transformer/RewriteRule.h
@@ -1,4 +1,4 @@
-//===--- Transformer.h - Clang source-rewriting library ---------*- C++ -*-===//
+//===--- RewriteRule.h - RewriteRule class ----------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,42 +7,30 @@
//===----------------------------------------------------------------------===//
///
/// \file
-/// Defines a library supporting the concise specification of clang-based
-/// source-to-source transformations.
+/// Defines the RewriteRule class and related functions for creating,
+/// modifying and interpreting RewriteRules.
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLING_REFACTOR_TRANSFORMER_H_
-#define LLVM_CLANG_TOOLING_REFACTOR_TRANSFORMER_H_
+#ifndef LLVM_CLANG_TOOLING_TRANSFORMER_REWRITE_RULE_H_
+#define LLVM_CLANG_TOOLING_TRANSFORMER_REWRITE_RULE_H_
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchersInternal.h"
#include "clang/Tooling/Refactoring/AtomicChange.h"
-#include "clang/Tooling/Refactoring/RangeSelector.h"
+#include "clang/Tooling/Transformer/MatchConsumer.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Error.h"
-#include <deque>
#include <functional>
#include <string>
-#include <type_traits>
#include <utility>
namespace clang {
-namespace tooling {
-
-// Note that \p TextGenerator is allowed to fail, e.g. when trying to access a
-// matched node that was not bound. Allowing this to fail simplifies error
-// handling for interactive tools like clang-query.
-using TextGenerator = std::function<Expected<std::string>(
- const ast_matchers::MatchFinder::MatchResult &)>;
-
-/// Wraps a string as a TextGenerator.
-inline TextGenerator text(std::string M) {
- return [M](const ast_matchers::MatchFinder::MatchResult &)
- -> Expected<std::string> { return M; };
-}
+namespace transformer {
+using TextGenerator = MatchConsumer<std::string>;
// Description of a source-code edit, expressed in terms of an AST node.
// Includes: an ID for the (bound) node, a selector for source related to the
@@ -160,11 +148,9 @@ inline RewriteRule makeRule(ast_matchers::internal::DynTypedMatcher M,
void addInclude(RewriteRule &Rule, llvm::StringRef Header,
IncludeFormat Format = IncludeFormat::Quoted);
-/// Applies the first rule whose pattern matches; other rules are ignored.
-///
-/// N.B. All of the rules must use the same kind of matcher (that is, share a
-/// base class in the AST hierarchy). However, this constraint is caused by an
-/// implementation detail and should be lifted in the future.
+/// Applies the first rule whose pattern matches; other rules are ignored. If
+/// the matchers are independent then order doesn't matter. In that case,
+/// `applyFirst` is simply joining the set of rules into one.
//
// `applyFirst` is like an `anyOf` matcher with an edit action attached to each
// of its cases. Anywhere you'd use `anyOf(m1.bind("id1"), m2.bind("id2"))` and
@@ -230,7 +216,9 @@ inline ASTEdit insertAfter(RangeSelector S, TextGenerator Replacement) {
/// Removes the source selected by \p S.
inline ASTEdit remove(RangeSelector S) {
- return change(std::move(S), text(""));
+ return change(std::move(S),
+ [](const ast_matchers::MatchFinder::MatchResult &)
+ -> Expected<std::string> { return ""; });
}
/// The following three functions are a low-level part of the RewriteRule
@@ -243,8 +231,25 @@ inline ASTEdit remove(RangeSelector S) {
// public and well-supported and move them out of `detail`.
namespace detail {
/// Builds a single matcher for the rule, covering all of the rule's cases.
+/// Only supports Rules whose cases' matchers share the same base "kind"
+/// (`Stmt`, `Decl`, etc.) Deprecated: use `buildMatchers` instead, which
+/// supports mixing matchers of different kinds.
ast_matchers::internal::DynTypedMatcher buildMatcher(const RewriteRule &Rule);
+/// Builds a set of matchers that cover the rule (one for each distinct node
+/// matcher base kind: Stmt, Decl, etc.). Node-matchers for `QualType` and
+/// `Type` are not permitted, since such nodes carry no source location
+/// information and are therefore not relevant for rewriting. If any such
+/// matchers are included, will return an empty vector.
+std::vector<ast_matchers::internal::DynTypedMatcher>
+buildMatchers(const RewriteRule &Rule);
+
+/// Gets the beginning location of the source matched by a rewrite rule. If the
+/// match occurs within a macro expansion, returns the beginning of the
+/// expansion point. `Result` must come from the matching of a rewrite rule.
+SourceLocation
+getRuleMatchLoc(const ast_matchers::MatchFinder::MatchResult &Result);
+
/// Returns the \c Case of \c Rule that was selected in the match result.
/// Assumes a matcher built with \c buildMatcher.
const RewriteRule::Case &
@@ -273,36 +278,32 @@ Expected<SmallVector<Transformation, 1>>
translateEdits(const ast_matchers::MatchFinder::MatchResult &Result,
llvm::ArrayRef<ASTEdit> Edits);
} // namespace detail
+} // namespace transformer
-/// Handles the matcher and callback registration for a single rewrite rule, as
-/// defined by the arguments of the constructor.
-class Transformer : public ast_matchers::MatchFinder::MatchCallback {
-public:
- using ChangeConsumer =
- std::function<void(Expected<clang::tooling::AtomicChange> Change)>;
-
- /// \param Consumer Receives each rewrite or error. Will not necessarily be
- /// called for each match; for example, if the rewrite is not applicable
- /// because of macros, but doesn't fail. Note that clients are responsible
- /// for handling the case that independent \c AtomicChanges conflict with each
- /// other.
- Transformer(RewriteRule Rule, ChangeConsumer Consumer)
- : Rule(std::move(Rule)), Consumer(std::move(Consumer)) {}
-
- /// N.B. Passes `this` pointer to `MatchFinder`. So, this object should not
- /// be moved after this call.
- void registerMatchers(ast_matchers::MatchFinder *MatchFinder);
+namespace tooling {
+// DEPRECATED: These are temporary aliases supporting client migration to the
+// `transformer` namespace.
+/// Wraps a string as a TextGenerator.
+using TextGenerator = transformer::TextGenerator;
- /// Not called directly by users -- called by the framework, via base class
- /// pointer.
- void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
+inline TextGenerator text(std::string M) {
+ return [M](const ast_matchers::MatchFinder::MatchResult &)
+ -> Expected<std::string> { return M; };
+}
-private:
- RewriteRule Rule;
- /// Receives each successful rewrites as an \c AtomicChange.
- ChangeConsumer Consumer;
-};
+using transformer::addInclude;
+using transformer::applyFirst;
+using transformer::change;
+using transformer::insertAfter;
+using transformer::insertBefore;
+using transformer::makeRule;
+using transformer::remove;
+using transformer::RewriteRule;
+using transformer::IncludeFormat;
+namespace detail {
+using namespace transformer::detail;
+} // namespace detail
} // namespace tooling
} // namespace clang
-#endif // LLVM_CLANG_TOOLING_REFACTOR_TRANSFORMER_H_
+#endif // LLVM_CLANG_TOOLING_TRANSFORMER_REWRITE_RULE_H_
diff --git a/include/clang/Tooling/Refactoring/SourceCode.h b/include/clang/Tooling/Transformer/SourceCode.h
index 498dbea96c70..bc9cc3d2a258 100644
--- a/include/clang/Tooling/Refactoring/SourceCode.h
+++ b/include/clang/Tooling/Transformer/SourceCode.h
@@ -10,8 +10,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLING_REFACTOR_SOURCE_CODE_H
-#define LLVM_CLANG_TOOLING_REFACTOR_SOURCE_CODE_H
+#ifndef LLVM_CLANG_TOOLING_TRANSFORMER_SOURCE_CODE_H
+#define LLVM_CLANG_TOOLING_TRANSFORMER_SOURCE_CODE_H
#include "clang/AST/ASTContext.h"
#include "clang/Basic/SourceLocation.h"
@@ -72,6 +72,19 @@ StringRef getExtendedText(const T &Node, tok::TokenKind Next,
ASTContext &Context) {
return getText(getExtendedRange(Node, Next, Context), Context);
}
+
+// Attempts to resolve the given range to one that can be edited by a rewrite;
+// generally, one that starts and ends within a particular file. It supports
+// a limited set of cases involving source locations in macro expansions.
+llvm::Optional<CharSourceRange>
+getRangeForEdit(const CharSourceRange &EditRange, const SourceManager &SM,
+ const LangOptions &LangOpts);
+
+inline llvm::Optional<CharSourceRange>
+getRangeForEdit(const CharSourceRange &EditRange, const ASTContext &Context) {
+ return getRangeForEdit(EditRange, Context.getSourceManager(),
+ Context.getLangOpts());
+}
} // namespace tooling
} // namespace clang
-#endif // LLVM_CLANG_TOOLING_REFACTOR_SOURCE_CODE_H
+#endif // LLVM_CLANG_TOOLING_TRANSFORMER_SOURCE_CODE_H
diff --git a/include/clang/Tooling/Transformer/SourceCodeBuilders.h b/include/clang/Tooling/Transformer/SourceCodeBuilders.h
new file mode 100644
index 000000000000..6c79a7588f28
--- /dev/null
+++ b/include/clang/Tooling/Transformer/SourceCodeBuilders.h
@@ -0,0 +1,86 @@
+//===--- SourceCodeBuilders.h - Source-code building facilities -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file collects facilities for generating source code strings.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_TRANSFORMER_SOURCE_CODE_BUILDERS_H_
+#define LLVM_CLANG_TOOLING_TRANSFORMER_SOURCE_CODE_BUILDERS_H_
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include <string>
+
+namespace clang {
+namespace tooling {
+
+/// \name Code analysis utilities.
+/// @{
+/// Ignores implicit object-construction expressions in addition to the normal
+/// implicit expressions that are ignored.
+const Expr *reallyIgnoreImplicit(const Expr &E);
+
+/// Determines whether printing this expression in *any* expression requires
+/// parentheses to preserve its meaning. This analyses is necessarily
+/// conservative because it lacks information about the target context.
+bool mayEverNeedParens(const Expr &E);
+
+/// Determines whether printing this expression to the left of a dot or arrow
+/// operator requires a parentheses to preserve its meaning. Given that
+/// dot/arrow are (effectively) the highest precedence, this is equivalent to
+/// asking whether it ever needs parens.
+inline bool needParensBeforeDotOrArrow(const Expr &E) {
+ return mayEverNeedParens(E);
+}
+
+/// Determines whether printing this expression to the right of a unary operator
+/// requires a parentheses to preserve its meaning.
+bool needParensAfterUnaryOperator(const Expr &E);
+/// @}
+
+/// \name Basic code-string generation utilities.
+/// @{
+
+/// Builds source for an expression, adding parens if needed for unambiguous
+/// parsing.
+llvm::Optional<std::string> buildParens(const Expr &E,
+ const ASTContext &Context);
+
+/// Builds idiomatic source for the dereferencing of `E`: prefix with `*` but
+/// simplify when it already begins with `&`. \returns empty string on failure.
+llvm::Optional<std::string> buildDereference(const Expr &E,
+ const ASTContext &Context);
+
+/// Builds idiomatic source for taking the address of `E`: prefix with `&` but
+/// simplify when it already begins with `*`. \returns empty string on failure.
+llvm::Optional<std::string> buildAddressOf(const Expr &E,
+ const ASTContext &Context);
+
+/// Adds a dot to the end of the given expression, but adds parentheses when
+/// needed by the syntax, and simplifies to `->` when possible, e.g.:
+///
+/// `x` becomes `x.`
+/// `*a` becomes `a->`
+/// `a+b` becomes `(a+b).`
+llvm::Optional<std::string> buildDot(const Expr &E, const ASTContext &Context);
+
+/// Adds an arrow to the end of the given expression, but adds parentheses
+/// when needed by the syntax, and simplifies to `.` when possible, e.g.:
+///
+/// `x` becomes `x->`
+/// `&a` becomes `a.`
+/// `a+b` becomes `(a+b)->`
+llvm::Optional<std::string> buildArrow(const Expr &E,
+ const ASTContext &Context);
+/// @}
+
+} // namespace tooling
+} // namespace clang
+#endif // LLVM_CLANG_TOOLING_TRANSFORMER_SOURCE_CODE_BUILDERS_H_
diff --git a/include/clang/Tooling/Refactoring/Stencil.h b/include/clang/Tooling/Transformer/Stencil.h
index e57a576e5575..66d1388f9710 100644
--- a/include/clang/Tooling/Refactoring/Stencil.h
+++ b/include/clang/Tooling/Transformer/Stencil.h
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
///
-/// /file
+/// \file
/// This file defines the *Stencil* abstraction: a code-generating object,
/// parameterized by named references to (bound) AST nodes. Given a match
/// result, a stencil can be evaluated to a string of source code.
@@ -17,21 +17,21 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLING_REFACTOR_STENCIL_H_
-#define LLVM_CLANG_TOOLING_REFACTOR_STENCIL_H_
+#ifndef LLVM_CLANG_TOOLING_TRANSFORMER_STENCIL_H_
+#define LLVM_CLANG_TOOLING_TRANSFORMER_STENCIL_H_
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTTypeTraits.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/Tooling/Refactoring/RangeSelector.h"
+#include "clang/Tooling/Transformer/MatchConsumer.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include <string>
#include <vector>
namespace clang {
-namespace tooling {
-
+namespace transformer {
/// A stencil is represented as a sequence of "parts" that can each individually
/// generate a code string based on a match result. The different kinds of
/// parts include (raw) text, references to bound nodes and assorted operations
@@ -47,21 +47,18 @@ public:
virtual llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &Match,
std::string *Result) const = 0;
- virtual bool isEqual(const StencilPartInterface &other) const = 0;
-
- const void *typeId() const { return TypeId; }
+ /// Constructs a string representation of the StencilPart. StencilParts
+ /// generated by the `selection` and `run` functions do not have a unique
+ /// string representation.
+ virtual std::string toString() const = 0;
protected:
- StencilPartInterface(const void *DerivedId) : TypeId(DerivedId) {}
+ StencilPartInterface() = default;
// Since this is an abstract class, copying/assigning only make sense for
// derived classes implementing `clone()`.
StencilPartInterface(const StencilPartInterface &) = default;
StencilPartInterface &operator=(const StencilPartInterface &) = default;
-
- /// Unique identifier of the concrete type of this instance. Supports safe
- /// downcasting.
- const void *TypeId;
};
/// A copyable facade for a std::unique_ptr<StencilPartInterface>. Copies result
@@ -77,12 +74,10 @@ public:
return Impl->eval(Match, Result);
}
- bool operator==(const StencilPart &Other) const {
- if (Impl == Other.Impl)
- return true;
- if (Impl == nullptr || Other.Impl == nullptr)
- return false;
- return Impl->isEqual(*Other.Impl);
+ std::string toString() const {
+ if (Impl == nullptr)
+ return "";
+ return Impl->toString();
}
private:
@@ -119,8 +114,17 @@ public:
return eval(Result);
}
+ /// Constructs a string representation of the Stencil. The string is not
+ /// guaranteed to be unique.
+ std::string toString() const {
+ std::vector<std::string> PartStrings;
+ PartStrings.reserve(Parts.size());
+ for (const auto &Part : Parts)
+ PartStrings.push_back(Part.toString());
+ return llvm::join(PartStrings, ", ");
+ }
+
private:
- friend bool operator==(const Stencil &A, const Stencil &B);
static StencilPart wrap(llvm::StringRef Text);
static StencilPart wrap(RangeSelector Selector);
static StencilPart wrap(StencilPart Part) { return Part; }
@@ -128,14 +132,10 @@ private:
std::vector<StencilPart> Parts;
};
-inline bool operator==(const Stencil &A, const Stencil &B) {
- return A.Parts == B.Parts;
-}
-
-inline bool operator!=(const Stencil &A, const Stencil &B) { return !(A == B); }
-
+//
// Functions for conveniently building stencils.
-namespace stencil {
+//
+
/// Convenience wrapper for Stencil::cat that can be imported with a using decl.
template <typename... Ts> Stencil cat(Ts &&... Parts) {
return Stencil::cat(std::forward<Ts>(Parts)...);
@@ -147,27 +147,75 @@ StencilPart text(llvm::StringRef Text);
/// \returns the source corresponding to the selected range.
StencilPart selection(RangeSelector Selector);
-/// \returns the source corresponding to the identified node.
-/// FIXME: Deprecated. Write `selection(node(Id))` instead.
-inline StencilPart node(llvm::StringRef Id) {
- return selection(tooling::node(Id));
+/// Generates the source of the expression bound to \p Id, wrapping it in
+/// parentheses if it may parse differently depending on context. For example, a
+/// binary operation is always wrapped, while a variable reference is never
+/// wrapped.
+StencilPart expression(llvm::StringRef Id);
+
+/// Constructs an idiomatic dereferencing of the expression bound to \p ExprId.
+/// \p ExprId is wrapped in parentheses, if needed.
+StencilPart deref(llvm::StringRef ExprId);
+
+/// Constructs an expression that idiomatically takes the address of the
+/// expression bound to \p ExprId. \p ExprId is wrapped in parentheses, if
+/// needed.
+StencilPart addressOf(llvm::StringRef ExprId);
+
+/// Constructs a `MemberExpr` that accesses the named member (\p Member) of the
+/// object bound to \p BaseId. The access is constructed idiomatically: if \p
+/// BaseId is bound to `e` and \p Member identifies member `m`, then returns
+/// `e->m`, when e is a pointer, `e2->m` when e = `*e2` and `e.m` otherwise.
+/// Additionally, `e` is wrapped in parentheses, if needed.
+StencilPart access(llvm::StringRef BaseId, StencilPart Member);
+inline StencilPart access(llvm::StringRef BaseId, llvm::StringRef Member) {
+ return access(BaseId, text(Member));
}
-/// Variant of \c node() that identifies the node as a statement, for purposes
-/// of deciding whether to include any trailing semicolon. Only relevant for
-/// Expr nodes, which, by default, are *not* considered as statements.
-/// \returns the source corresponding to the identified node, considered as a
-/// statement.
-/// FIXME: Deprecated. Write `selection(statement(Id))` instead.
-inline StencilPart sNode(llvm::StringRef Id) {
- return selection(tooling::statement(Id));
+/// Chooses between the two stencil parts, based on whether \p ID is bound in
+/// the match.
+StencilPart ifBound(llvm::StringRef Id, StencilPart TruePart,
+ StencilPart FalsePart);
+
+/// Chooses between the two strings, based on whether \p ID is bound in the
+/// match.
+inline StencilPart ifBound(llvm::StringRef Id, llvm::StringRef TrueText,
+ llvm::StringRef FalseText) {
+ return ifBound(Id, text(TrueText), text(FalseText));
}
+/// Wraps a MatchConsumer in a StencilPart, so that it can be used in a Stencil.
+/// This supports user-defined extensions to the Stencil language.
+StencilPart run(MatchConsumer<std::string> C);
+
/// For debug use only; semantics are not guaranteed.
///
/// \returns the string resulting from calling the node's print() method.
StencilPart dPrint(llvm::StringRef Id);
+} // namespace transformer
+
+namespace tooling {
+// DEPRECATED: These are temporary aliases supporting client migration to the
+// `transformer` namespace.
+using Stencil = transformer::Stencil;
+using StencilPart = transformer::StencilPart;
+namespace stencil {
+using transformer::access;
+using transformer::addressOf;
+using transformer::cat;
+using transformer::deref;
+using transformer::dPrint;
+using transformer::expression;
+using transformer::ifBound;
+using transformer::run;
+using transformer::selection;
+using transformer::text;
+/// \returns the source corresponding to the identified node.
+/// FIXME: Deprecated. Write `selection(node(Id))` instead.
+inline transformer::StencilPart node(llvm::StringRef Id) {
+ return selection(tooling::node(Id));
+}
} // namespace stencil
} // namespace tooling
} // namespace clang
-#endif // LLVM_CLANG_TOOLING_REFACTOR_STENCIL_H_
+#endif // LLVM_CLANG_TOOLING_TRANSFORMER_STENCIL_H_
diff --git a/include/clang/Tooling/Transformer/Transformer.h b/include/clang/Tooling/Transformer/Transformer.h
new file mode 100644
index 000000000000..31feacba5e28
--- /dev/null
+++ b/include/clang/Tooling/Transformer/Transformer.h
@@ -0,0 +1,52 @@
+//===--- Transformer.h - Transformer class ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_TRANSFORMER_TRANSFORMER_H_
+#define LLVM_CLANG_TOOLING_TRANSFORMER_TRANSFORMER_H_
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "clang/Tooling/Transformer/RewriteRule.h"
+#include "llvm/Support/Error.h"
+#include <functional>
+#include <utility>
+
+namespace clang {
+namespace tooling {
+/// Handles the matcher and callback registration for a single `RewriteRule`, as
+/// defined by the arguments of the constructor.
+class Transformer : public ast_matchers::MatchFinder::MatchCallback {
+public:
+ using ChangeConsumer =
+ std::function<void(Expected<clang::tooling::AtomicChange> Change)>;
+
+ /// \param Consumer Receives each rewrite or error. Will not necessarily be
+ /// called for each match; for example, if the rewrite is not applicable
+ /// because of macros, but doesn't fail. Note that clients are responsible
+ /// for handling the case that independent \c AtomicChanges conflict with each
+ /// other.
+ Transformer(transformer::RewriteRule Rule, ChangeConsumer Consumer)
+ : Rule(std::move(Rule)), Consumer(std::move(Consumer)) {}
+
+ /// N.B. Passes `this` pointer to `MatchFinder`. So, this object should not
+ /// be moved after this call.
+ void registerMatchers(ast_matchers::MatchFinder *MatchFinder);
+
+ /// Not called directly by users -- called by the framework, via base class
+ /// pointer.
+ void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ transformer::RewriteRule Rule;
+ /// Receives each successful rewrites as an \c AtomicChange.
+ ChangeConsumer Consumer;
+};
+} // namespace tooling
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLING_TRANSFORMER_TRANSFORMER_H_
diff --git a/include/clang/module.modulemap b/include/clang/module.modulemap
index 1f32ffe0c159..2cbe865bce87 100644
--- a/include/clang/module.modulemap
+++ b/include/clang/module.modulemap
@@ -18,9 +18,9 @@ module Clang_AST {
umbrella "AST"
textual header "AST/BuiltinTypes.def"
+ textual header "AST/CXXRecordDeclDefinitionBits.def"
textual header "AST/OperationKinds.def"
textual header "AST/TypeLocNodes.def"
- textual header "AST/TypeNodes.def"
module * { export * }
}
@@ -31,9 +31,11 @@ module Clang_Basic {
requires cplusplus
umbrella "Basic"
+ textual header "Basic/AArch64SVEACLETypes.def"
textual header "Basic/BuiltinsAArch64.def"
textual header "Basic/BuiltinsAMDGPU.def"
textual header "Basic/BuiltinsARM.def"
+ textual header "Basic/BuiltinsBPF.def"
textual header "Basic/Builtins.def"
textual header "Basic/BuiltinsHexagon.def"
textual header "Basic/BuiltinsLe64.def"
@@ -100,7 +102,7 @@ module Clang_Frontend {
requires cplusplus
umbrella "Frontend"
- textual header "Frontend/LangStandards.def"
+ textual header "Basic/LangStandards.def"
module * { export * }
}
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index 568e06f21fba..a9018c1c4bdf 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -139,7 +139,7 @@ public:
}
// Non-ARC warnings are ignored.
- Diags.setLastDiagnosticIgnored();
+ Diags.setLastDiagnosticIgnored(true);
}
};
@@ -453,8 +453,8 @@ public:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override {
CI.getPreprocessor().addPPCallbacks(
- llvm::make_unique<ARCMTMacroTrackerPPCallbacks>(ARCMTMacroLocs));
- return llvm::make_unique<ASTConsumer>();
+ std::make_unique<ARCMTMacroTrackerPPCallbacks>(ARCMTMacroLocs));
+ return std::make_unique<ASTConsumer>();
}
};
diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp
index 1a4862d09aa6..a031fe22ac13 100644
--- a/lib/ARCMigrate/FileRemapper.cpp
+++ b/lib/ARCMigrate/FileRemapper.cpp
@@ -78,26 +78,26 @@ bool FileRemapper::initFromFile(StringRef filePath, DiagnosticsEngine &Diag,
Diag);
StringRef toFilename = lines[idx+2];
- const FileEntry *origFE = FileMgr->getFile(fromFilename);
+ llvm::ErrorOr<const FileEntry *> origFE = FileMgr->getFile(fromFilename);
if (!origFE) {
if (ignoreIfFilesChanged)
continue;
return report("File does not exist: " + fromFilename, Diag);
}
- const FileEntry *newFE = FileMgr->getFile(toFilename);
+ llvm::ErrorOr<const FileEntry *> newFE = FileMgr->getFile(toFilename);
if (!newFE) {
if (ignoreIfFilesChanged)
continue;
return report("File does not exist: " + toFilename, Diag);
}
- if ((uint64_t)origFE->getModificationTime() != timeModified) {
+ if ((uint64_t)(*origFE)->getModificationTime() != timeModified) {
if (ignoreIfFilesChanged)
continue;
return report("File was modified: " + fromFilename, Diag);
}
- pairs.push_back(std::make_pair(origFE, newFE));
+ pairs.push_back(std::make_pair(*origFE, *newFE));
}
for (unsigned i = 0, e = pairs.size(); i != e; ++i)
@@ -121,7 +121,7 @@ bool FileRemapper::flushToFile(StringRef outputPath, DiagnosticsEngine &Diag) {
std::error_code EC;
std::string infoFile = outputPath;
- llvm::raw_fd_ostream infoOut(infoFile, EC, llvm::sys::fs::F_None);
+ llvm::raw_fd_ostream infoOut(infoFile, EC, llvm::sys::fs::OF_None);
if (EC)
return report(EC.message(), Diag);
@@ -152,9 +152,11 @@ bool FileRemapper::flushToFile(StringRef outputPath, DiagnosticsEngine &Diag) {
newOut.write(mem->getBufferStart(), mem->getBufferSize());
newOut.close();
- const FileEntry *newE = FileMgr->getFile(tempPath);
- remap(origFE, newE);
- infoOut << newE->getName() << '\n';
+ auto newE = FileMgr->getFile(tempPath);
+ if (newE) {
+ remap(origFE, *newE);
+ infoOut << (*newE)->getName() << '\n';
+ }
}
}
@@ -175,7 +177,7 @@ bool FileRemapper::overwriteOriginal(DiagnosticsEngine &Diag,
Diag);
std::error_code EC;
- llvm::raw_fd_ostream Out(origFE->getName(), EC, llvm::sys::fs::F_None);
+ llvm::raw_fd_ostream Out(origFE->getName(), EC, llvm::sys::fs::OF_None);
if (EC)
return report(EC.message(), Diag);
@@ -224,7 +226,9 @@ void FileRemapper::remap(const FileEntry *file, const FileEntry *newfile) {
}
const FileEntry *FileRemapper::getOriginalFile(StringRef filePath) {
- const FileEntry *file = FileMgr->getFile(filePath);
+ const FileEntry *file = nullptr;
+ if (auto fileOrErr = FileMgr->getFile(filePath))
+ file = *fileOrErr;
// If we are updating a file that overridden an original file,
// actually update the original file.
llvm::DenseMap<const FileEntry *, const FileEntry *>::iterator
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index 7126a0873ea0..4abb04fef5b8 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -208,10 +208,10 @@ ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
CI.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
std::vector<std::unique_ptr<ASTConsumer>> Consumers;
Consumers.push_back(WrapperFrontendAction::CreateASTConsumer(CI, InFile));
- Consumers.push_back(llvm::make_unique<ObjCMigrateASTConsumer>(
+ Consumers.push_back(std::make_unique<ObjCMigrateASTConsumer>(
MigrateDir, ObjCMigAction, Remapper, CompInst->getFileManager(), PPRec,
CompInst->getPreprocessor(), false, None));
- return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
+ return std::make_unique<MultiplexConsumer>(std::move(Consumers));
}
bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
@@ -1951,7 +1951,7 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
if (IsOutputFile) {
std::error_code EC;
- llvm::raw_fd_ostream OS(MigrateDir, EC, llvm::sys::fs::F_None);
+ llvm::raw_fd_ostream OS(MigrateDir, EC, llvm::sys::fs::OF_None);
if (EC) {
DiagnosticsEngine &Diags = Ctx.getDiagnostics();
Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0"))
@@ -2034,7 +2034,7 @@ MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
CI.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
std::vector<std::string> WhiteList =
getWhiteListFilenames(CI.getFrontendOpts().ObjCMTWhiteListPath);
- return llvm::make_unique<ObjCMigrateASTConsumer>(
+ return std::make_unique<ObjCMigrateASTConsumer>(
CI.getFrontendOpts().OutputFile, ObjCMTAction, Remapper,
CI.getFileManager(), PPRec, CI.getPreprocessor(),
/*isOutputFile=*/true, WhiteList);
@@ -2141,10 +2141,11 @@ private:
StringRef Val = ValueString->getValue(ValueStorage);
if (Key == "file") {
- const FileEntry *FE = FileMgr.getFile(Val);
- if (!FE)
+ auto FE = FileMgr.getFile(Val);
+ if (FE)
+ Entry.File = *FE;
+ else
Ignore = true;
- Entry.File = FE;
} else if (Key == "offset") {
if (Val.getAsInteger(10, Entry.Offset))
Ignore = true;
diff --git a/lib/ARCMigrate/PlistReporter.cpp b/lib/ARCMigrate/PlistReporter.cpp
index 6d7fcb053b48..d01563b2974d 100644
--- a/lib/ARCMigrate/PlistReporter.cpp
+++ b/lib/ARCMigrate/PlistReporter.cpp
@@ -56,7 +56,7 @@ void arcmt::writeARCDiagsToPlist(const std::string &outPath,
}
std::error_code EC;
- llvm::raw_fd_ostream o(outPath, EC, llvm::sys::fs::F_Text);
+ llvm::raw_fd_ostream o(outPath, EC, llvm::sys::fs::OF_Text);
if (EC) {
llvm::errs() << "error: could not create file: " << outPath << '\n';
return;
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 1993bba9bd1a..50f8d05dacb4 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -42,6 +42,14 @@ APValue::LValueBase::LValueBase(const ValueDecl *P, unsigned I, unsigned V)
APValue::LValueBase::LValueBase(const Expr *P, unsigned I, unsigned V)
: Ptr(P), Local{I, V} {}
+APValue::LValueBase APValue::LValueBase::getDynamicAlloc(DynamicAllocLValue LV,
+ QualType Type) {
+ LValueBase Base;
+ Base.Ptr = LV;
+ Base.DynamicAllocType = Type.getAsOpaquePtr();
+ return Base;
+}
+
APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV,
QualType TypeInfo) {
LValueBase Base;
@@ -51,11 +59,12 @@ APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV,
}
unsigned APValue::LValueBase::getCallIndex() const {
- return is<TypeInfoLValue>() ? 0 : Local.CallIndex;
+ return (is<TypeInfoLValue>() || is<DynamicAllocLValue>()) ? 0
+ : Local.CallIndex;
}
unsigned APValue::LValueBase::getVersion() const {
- return is<TypeInfoLValue>() ? 0 : Local.Version;
+ return (is<TypeInfoLValue>() || is<DynamicAllocLValue>()) ? 0 : Local.Version;
}
QualType APValue::LValueBase::getTypeInfoType() const {
@@ -63,6 +72,11 @@ QualType APValue::LValueBase::getTypeInfoType() const {
return QualType::getFromOpaquePtr(TypeInfoType);
}
+QualType APValue::LValueBase::getDynamicAllocType() const {
+ assert(is<DynamicAllocLValue>() && "not a dynamic allocation lvalue");
+ return QualType::getFromOpaquePtr(DynamicAllocType);
+}
+
namespace clang {
bool operator==(const APValue::LValueBase &LHS,
const APValue::LValueBase &RHS) {
@@ -111,7 +125,7 @@ llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() {
namespace clang {
llvm::hash_code hash_value(const APValue::LValueBase &Base) {
- if (Base.is<TypeInfoLValue>())
+ if (Base.is<TypeInfoLValue>() || Base.is<DynamicAllocLValue>())
return llvm::hash_value(Base.getOpaqueValue());
return llvm::hash_combine(Base.getOpaqueValue(), Base.getCallIndex(),
Base.getVersion());
@@ -479,7 +493,7 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx,
return;
case APValue::Vector: {
Out << '{';
- QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ QualType ElemTy = Ty->castAs<VectorType>()->getElementType();
getVectorElt(0).printPretty(Out, Ctx, ElemTy);
for (unsigned i = 1; i != getVectorLength(); ++i) {
Out << ", ";
@@ -528,13 +542,18 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx,
S = CharUnits::One();
}
Out << '&';
- } else if (!IsReference)
+ } else if (!IsReference) {
Out << '&';
+ }
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
Out << *VD;
else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
TI.print(Out, Ctx.getPrintingPolicy());
+ } else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) {
+ Out << "{*new "
+ << Base.getDynamicAllocType().stream(Ctx.getPrintingPolicy()) << "#"
+ << DA.getIndex() << "}";
} else {
assert(Base.get<const Expr *>() != nullptr &&
"Expecting non-null Expr");
@@ -563,10 +582,17 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx,
} else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
TI.print(Out, Ctx.getPrintingPolicy());
ElemTy = Base.getTypeInfoType();
+ } else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) {
+ Out << "{*new "
+ << Base.getDynamicAllocType().stream(Ctx.getPrintingPolicy()) << "#"
+ << DA.getIndex() << "}";
+ ElemTy = Base.getDynamicAllocType();
} else {
const Expr *E = Base.get<const Expr*>();
assert(E != nullptr && "Expecting non-null Expr");
E->printPretty(Out, nullptr, Ctx.getPrintingPolicy());
+ // FIXME: This is wrong if E is a MaterializeTemporaryExpr with an lvalue
+ // adjustment.
ElemTy = E->getType();
}
@@ -626,7 +652,7 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx,
}
case APValue::Struct: {
Out << '{';
- const RecordDecl *RD = Ty->getAs<RecordType>()->getDecl();
+ const RecordDecl *RD = Ty->castAs<RecordType>()->getDecl();
bool First = true;
if (unsigned N = getStructNumBases()) {
const CXXRecordDecl *CD = cast<CXXRecordDecl>(RD);
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 0d69eb90abaf..cda51ec755a8 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/ASTContext.h"
#include "CXXABI.h"
+#include "Interp/Context.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/ASTTypeTraits.h"
@@ -98,62 +99,60 @@ enum FloatingRank {
Float16Rank, HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank
};
-RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
+/// \returns location that is relevant when searching for Doc comments related
+/// to \p D.
+static SourceLocation getDeclLocForCommentSearch(const Decl *D,
+ SourceManager &SourceMgr) {
assert(D);
- // If we already tried to load comments but there are none,
- // we won't find anything.
- if (CommentsLoaded && Comments.getComments().empty())
- return nullptr;
-
// User can not attach documentation to implicit declarations.
if (D->isImplicit())
- return nullptr;
+ return {};
// User can not attach documentation to implicit instantiations.
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
- return nullptr;
+ return {};
}
if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (VD->isStaticDataMember() &&
VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
- return nullptr;
+ return {};
}
if (const auto *CRD = dyn_cast<CXXRecordDecl>(D)) {
if (CRD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
- return nullptr;
+ return {};
}
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
TemplateSpecializationKind TSK = CTSD->getSpecializationKind();
if (TSK == TSK_ImplicitInstantiation ||
TSK == TSK_Undeclared)
- return nullptr;
+ return {};
}
if (const auto *ED = dyn_cast<EnumDecl>(D)) {
if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
- return nullptr;
+ return {};
}
if (const auto *TD = dyn_cast<TagDecl>(D)) {
// When tag declaration (but not definition!) is part of the
// decl-specifier-seq of some other declaration, it doesn't get comment
if (TD->isEmbeddedInDeclarator() && !TD->isCompleteDefinition())
- return nullptr;
+ return {};
}
// TODO: handle comments for function parameters properly.
if (isa<ParmVarDecl>(D))
- return nullptr;
+ return {};
// TODO: we could look up template parameter documentation in the template
// documentation.
if (isa<TemplateTypeParmDecl>(D) ||
isa<NonTypeTemplateParmDecl>(D) ||
isa<TemplateTemplateParmDecl>(D))
- return nullptr;
+ return {};
// Find declaration location.
// For Objective-C declarations we generally don't expect to have multiple
@@ -161,20 +160,19 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
// location".
// For all other declarations multiple declarators are used quite frequently,
// so we use the location of the identifier as the "declaration location".
- SourceLocation DeclLoc;
if (isa<ObjCMethodDecl>(D) || isa<ObjCContainerDecl>(D) ||
isa<ObjCPropertyDecl>(D) ||
isa<RedeclarableTemplateDecl>(D) ||
isa<ClassTemplateSpecializationDecl>(D))
- DeclLoc = D->getBeginLoc();
+ return D->getBeginLoc();
else {
- DeclLoc = D->getLocation();
+ const SourceLocation DeclLoc = D->getLocation();
if (DeclLoc.isMacroID()) {
if (isa<TypedefDecl>(D)) {
// If location of the typedef name is in a macro, it is because being
// declared via a macro. Try using declaration's starting location as
// the "declaration location".
- DeclLoc = D->getBeginLoc();
+ return D->getBeginLoc();
} else if (const auto *TD = dyn_cast<TagDecl>(D)) {
// If location of the tag decl is inside a macro, but the spelling of
// the tag name comes from a macro argument, it looks like a special
@@ -183,102 +181,73 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
// attach the comment to the tag decl.
if (SourceMgr.isMacroArgExpansion(DeclLoc) &&
TD->isCompleteDefinition())
- DeclLoc = SourceMgr.getExpansionLoc(DeclLoc);
+ return SourceMgr.getExpansionLoc(DeclLoc);
}
}
+ return DeclLoc;
}
+ return {};
+}
+
+RawComment *ASTContext::getRawCommentForDeclNoCacheImpl(
+ const Decl *D, const SourceLocation RepresentativeLocForDecl,
+ const std::map<unsigned, RawComment *> &CommentsInTheFile) const {
// If the declaration doesn't map directly to a location in a file, we
// can't find the comment.
- if (DeclLoc.isInvalid() || !DeclLoc.isFileID())
+ if (RepresentativeLocForDecl.isInvalid() ||
+ !RepresentativeLocForDecl.isFileID())
return nullptr;
- if (!CommentsLoaded && ExternalSource) {
- ExternalSource->ReadComments();
-
-#ifndef NDEBUG
- ArrayRef<RawComment *> RawComments = Comments.getComments();
- assert(std::is_sorted(RawComments.begin(), RawComments.end(),
- BeforeThanCompare<RawComment>(SourceMgr)));
-#endif
-
- CommentsLoaded = true;
- }
-
- ArrayRef<RawComment *> RawComments = Comments.getComments();
// If there are no comments anywhere, we won't find anything.
- if (RawComments.empty())
+ if (CommentsInTheFile.empty())
return nullptr;
- // Find the comment that occurs just after this declaration.
- ArrayRef<RawComment *>::iterator Comment;
- {
- // When searching for comments during parsing, the comment we are looking
- // for is usually among the last two comments we parsed -- check them
- // first.
- RawComment CommentAtDeclLoc(
- SourceMgr, SourceRange(DeclLoc), LangOpts.CommentOpts, false);
- BeforeThanCompare<RawComment> Compare(SourceMgr);
- ArrayRef<RawComment *>::iterator MaybeBeforeDecl = RawComments.end() - 1;
- bool Found = Compare(*MaybeBeforeDecl, &CommentAtDeclLoc);
- if (!Found && RawComments.size() >= 2) {
- MaybeBeforeDecl--;
- Found = Compare(*MaybeBeforeDecl, &CommentAtDeclLoc);
- }
-
- if (Found) {
- Comment = MaybeBeforeDecl + 1;
- assert(Comment ==
- llvm::lower_bound(RawComments, &CommentAtDeclLoc, Compare));
- } else {
- // Slow path.
- Comment = llvm::lower_bound(RawComments, &CommentAtDeclLoc, Compare);
- }
- }
-
// Decompose the location for the declaration and find the beginning of the
// file buffer.
- std::pair<FileID, unsigned> DeclLocDecomp = SourceMgr.getDecomposedLoc(DeclLoc);
+ const std::pair<FileID, unsigned> DeclLocDecomp =
+ SourceMgr.getDecomposedLoc(RepresentativeLocForDecl);
+
+ // Slow path.
+ auto OffsetCommentBehindDecl =
+ CommentsInTheFile.lower_bound(DeclLocDecomp.second);
// First check whether we have a trailing comment.
- if (Comment != RawComments.end() &&
- ((*Comment)->isDocumentation() || LangOpts.CommentOpts.ParseAllComments)
- && (*Comment)->isTrailingComment() &&
- (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D) ||
- isa<ObjCMethodDecl>(D) || isa<ObjCPropertyDecl>(D))) {
- std::pair<FileID, unsigned> CommentBeginDecomp
- = SourceMgr.getDecomposedLoc((*Comment)->getSourceRange().getBegin());
- // Check that Doxygen trailing comment comes after the declaration, starts
- // on the same line and in the same file as the declaration.
- if (DeclLocDecomp.first == CommentBeginDecomp.first &&
- SourceMgr.getLineNumber(DeclLocDecomp.first, DeclLocDecomp.second)
- == SourceMgr.getLineNumber(CommentBeginDecomp.first,
- CommentBeginDecomp.second)) {
- (**Comment).setAttached();
- return *Comment;
+ if (OffsetCommentBehindDecl != CommentsInTheFile.end()) {
+ RawComment *CommentBehindDecl = OffsetCommentBehindDecl->second;
+ if ((CommentBehindDecl->isDocumentation() ||
+ LangOpts.CommentOpts.ParseAllComments) &&
+ CommentBehindDecl->isTrailingComment() &&
+ (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D) ||
+ isa<ObjCMethodDecl>(D) || isa<ObjCPropertyDecl>(D))) {
+
+ // Check that Doxygen trailing comment comes after the declaration, starts
+ // on the same line and in the same file as the declaration.
+ if (SourceMgr.getLineNumber(DeclLocDecomp.first, DeclLocDecomp.second) ==
+ Comments.getCommentBeginLine(CommentBehindDecl, DeclLocDecomp.first,
+ OffsetCommentBehindDecl->first)) {
+ return CommentBehindDecl;
+ }
}
}
// The comment just after the declaration was not a trailing comment.
// Let's look at the previous comment.
- if (Comment == RawComments.begin())
+ if (OffsetCommentBehindDecl == CommentsInTheFile.begin())
return nullptr;
- --Comment;
+
+ auto OffsetCommentBeforeDecl = --OffsetCommentBehindDecl;
+ RawComment *CommentBeforeDecl = OffsetCommentBeforeDecl->second;
// Check that we actually have a non-member Doxygen comment.
- if (!((*Comment)->isDocumentation() ||
+ if (!(CommentBeforeDecl->isDocumentation() ||
LangOpts.CommentOpts.ParseAllComments) ||
- (*Comment)->isTrailingComment())
+ CommentBeforeDecl->isTrailingComment())
return nullptr;
// Decompose the end of the comment.
- std::pair<FileID, unsigned> CommentEndDecomp
- = SourceMgr.getDecomposedLoc((*Comment)->getSourceRange().getEnd());
-
- // If the comment and the declaration aren't in the same file, then they
- // aren't related.
- if (DeclLocDecomp.first != CommentEndDecomp.first)
- return nullptr;
+ const unsigned CommentEndOffset =
+ Comments.getCommentEndOffset(CommentBeforeDecl);
// Get the corresponding buffer.
bool Invalid = false;
@@ -288,26 +257,49 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
return nullptr;
// Extract text between the comment and declaration.
- StringRef Text(Buffer + CommentEndDecomp.second,
- DeclLocDecomp.second - CommentEndDecomp.second);
+ StringRef Text(Buffer + CommentEndOffset,
+ DeclLocDecomp.second - CommentEndOffset);
// There should be no other declarations or preprocessor directives between
// comment and declaration.
if (Text.find_first_of(";{}#@") != StringRef::npos)
return nullptr;
- (**Comment).setAttached();
- return *Comment;
+ return CommentBeforeDecl;
+}
+
+RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
+ const SourceLocation DeclLoc = getDeclLocForCommentSearch(D, SourceMgr);
+
+ // If the declaration doesn't map directly to a location in a file, we
+ // can't find the comment.
+ if (DeclLoc.isInvalid() || !DeclLoc.isFileID())
+ return nullptr;
+
+ if (ExternalSource && !CommentsLoaded) {
+ ExternalSource->ReadComments();
+ CommentsLoaded = true;
+ }
+
+ if (Comments.empty())
+ return nullptr;
+
+ const FileID File = SourceMgr.getDecomposedLoc(DeclLoc).first;
+ const auto CommentsInThisFile = Comments.getCommentsInFile(File);
+ if (!CommentsInThisFile || CommentsInThisFile->empty())
+ return nullptr;
+
+ return getRawCommentForDeclNoCacheImpl(D, DeclLoc, *CommentsInThisFile);
}
/// If we have a 'templated' declaration for a template, adjust 'D' to
/// refer to the actual template.
/// If we have an implicit instantiation, adjust 'D' to refer to template.
-static const Decl *adjustDeclToTemplate(const Decl *D) {
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+static const Decl &adjustDeclToTemplate(const Decl &D) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(&D)) {
// Is this function declaration part of a function template?
if (const FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate())
- return FTD;
+ return *FTD;
// Nothing to do if function is not an implicit instantiation.
if (FD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation)
@@ -315,28 +307,28 @@ static const Decl *adjustDeclToTemplate(const Decl *D) {
// Function is an implicit instantiation of a function template?
if (const FunctionTemplateDecl *FTD = FD->getPrimaryTemplate())
- return FTD;
+ return *FTD;
// Function is instantiated from a member definition of a class template?
if (const FunctionDecl *MemberDecl =
FD->getInstantiatedFromMemberFunction())
- return MemberDecl;
+ return *MemberDecl;
return D;
}
- if (const auto *VD = dyn_cast<VarDecl>(D)) {
+ if (const auto *VD = dyn_cast<VarDecl>(&D)) {
// Static data member is instantiated from a member definition of a class
// template?
if (VD->isStaticDataMember())
if (const VarDecl *MemberDecl = VD->getInstantiatedFromStaticDataMember())
- return MemberDecl;
+ return *MemberDecl;
return D;
}
- if (const auto *CRD = dyn_cast<CXXRecordDecl>(D)) {
+ if (const auto *CRD = dyn_cast<CXXRecordDecl>(&D)) {
// Is this class declaration part of a class template?
if (const ClassTemplateDecl *CTD = CRD->getDescribedClassTemplate())
- return CTD;
+ return *CTD;
// Class is an implicit instantiation of a class template or partial
// specialization?
@@ -346,23 +338,23 @@ static const Decl *adjustDeclToTemplate(const Decl *D) {
llvm::PointerUnion<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *>
PU = CTSD->getSpecializedTemplateOrPartial();
- return PU.is<ClassTemplateDecl*>() ?
- static_cast<const Decl*>(PU.get<ClassTemplateDecl *>()) :
- static_cast<const Decl*>(
- PU.get<ClassTemplatePartialSpecializationDecl *>());
+ return PU.is<ClassTemplateDecl *>()
+ ? *static_cast<const Decl *>(PU.get<ClassTemplateDecl *>())
+ : *static_cast<const Decl *>(
+ PU.get<ClassTemplatePartialSpecializationDecl *>());
}
// Class is instantiated from a member definition of a class template?
if (const MemberSpecializationInfo *Info =
- CRD->getMemberSpecializationInfo())
- return Info->getInstantiatedFrom();
+ CRD->getMemberSpecializationInfo())
+ return *Info->getInstantiatedFrom();
return D;
}
- if (const auto *ED = dyn_cast<EnumDecl>(D)) {
+ if (const auto *ED = dyn_cast<EnumDecl>(&D)) {
// Enum is instantiated from a member definition of a class template?
if (const EnumDecl *MemberDecl = ED->getInstantiatedFromMemberEnum())
- return MemberDecl;
+ return *MemberDecl;
return D;
}
@@ -373,72 +365,81 @@ static const Decl *adjustDeclToTemplate(const Decl *D) {
const RawComment *ASTContext::getRawCommentForAnyRedecl(
const Decl *D,
const Decl **OriginalDecl) const {
- D = adjustDeclToTemplate(D);
+ if (!D) {
+ if (OriginalDecl)
+ OriginalDecl = nullptr;
+ return nullptr;
+ }
- // Check whether we have cached a comment for this declaration already.
+ D = &adjustDeclToTemplate(*D);
+
+ // Any comment directly attached to D?
{
- llvm::DenseMap<const Decl *, RawCommentAndCacheFlags>::iterator Pos =
- RedeclComments.find(D);
- if (Pos != RedeclComments.end()) {
- const RawCommentAndCacheFlags &Raw = Pos->second;
- if (Raw.getKind() != RawCommentAndCacheFlags::NoCommentInDecl) {
- if (OriginalDecl)
- *OriginalDecl = Raw.getOriginalDecl();
- return Raw.getRaw();
- }
+ auto DeclComment = DeclRawComments.find(D);
+ if (DeclComment != DeclRawComments.end()) {
+ if (OriginalDecl)
+ *OriginalDecl = D;
+ return DeclComment->second;
}
}
- // Search for comments attached to declarations in the redeclaration chain.
- const RawComment *RC = nullptr;
- const Decl *OriginalDeclForRC = nullptr;
- for (auto I : D->redecls()) {
- llvm::DenseMap<const Decl *, RawCommentAndCacheFlags>::iterator Pos =
- RedeclComments.find(I);
- if (Pos != RedeclComments.end()) {
- const RawCommentAndCacheFlags &Raw = Pos->second;
- if (Raw.getKind() != RawCommentAndCacheFlags::NoCommentInDecl) {
- RC = Raw.getRaw();
- OriginalDeclForRC = Raw.getOriginalDecl();
- break;
- }
- } else {
- RC = getRawCommentForDeclNoCache(I);
- OriginalDeclForRC = I;
- RawCommentAndCacheFlags Raw;
- if (RC) {
- // Call order swapped to work around ICE in VS2015 RTM (Release Win32)
- // https://connect.microsoft.com/VisualStudio/feedback/details/1741530
- Raw.setKind(RawCommentAndCacheFlags::FromDecl);
- Raw.setRaw(RC);
- } else
- Raw.setKind(RawCommentAndCacheFlags::NoCommentInDecl);
- Raw.setOriginalDecl(I);
- RedeclComments[I] = Raw;
- if (RC)
- break;
+ // Any comment attached to any redeclaration of D?
+ const Decl *CanonicalD = D->getCanonicalDecl();
+ if (!CanonicalD)
+ return nullptr;
+
+ {
+ auto RedeclComment = RedeclChainComments.find(CanonicalD);
+ if (RedeclComment != RedeclChainComments.end()) {
+ if (OriginalDecl)
+ *OriginalDecl = RedeclComment->second;
+ auto CommentAtRedecl = DeclRawComments.find(RedeclComment->second);
+ assert(CommentAtRedecl != DeclRawComments.end() &&
+ "This decl is supposed to have comment attached.");
+ return CommentAtRedecl->second;
}
}
- // If we found a comment, it should be a documentation comment.
- assert(!RC || RC->isDocumentation() || LangOpts.CommentOpts.ParseAllComments);
+ // Any redeclarations of D that we haven't checked for comments yet?
+ // We can't use DenseMap::iterator directly since it'd get invalid.
+ auto LastCheckedRedecl = [this, CanonicalD]() -> const Decl * {
+ auto LookupRes = CommentlessRedeclChains.find(CanonicalD);
+ if (LookupRes != CommentlessRedeclChains.end())
+ return LookupRes->second;
+ return nullptr;
+ }();
+
+ for (const auto Redecl : D->redecls()) {
+ assert(Redecl);
+ // Skip all redeclarations that have been checked previously.
+ if (LastCheckedRedecl) {
+ if (LastCheckedRedecl == Redecl) {
+ LastCheckedRedecl = nullptr;
+ }
+ continue;
+ }
+ const RawComment *RedeclComment = getRawCommentForDeclNoCache(Redecl);
+ if (RedeclComment) {
+ cacheRawCommentForDecl(*Redecl, *RedeclComment);
+ if (OriginalDecl)
+ *OriginalDecl = Redecl;
+ return RedeclComment;
+ }
+ CommentlessRedeclChains[CanonicalD] = Redecl;
+ }
if (OriginalDecl)
- *OriginalDecl = OriginalDeclForRC;
-
- // Update cache for every declaration in the redeclaration chain.
- RawCommentAndCacheFlags Raw;
- Raw.setRaw(RC);
- Raw.setKind(RawCommentAndCacheFlags::FromRedecl);
- Raw.setOriginalDecl(OriginalDeclForRC);
-
- for (auto I : D->redecls()) {
- RawCommentAndCacheFlags &R = RedeclComments[I];
- if (R.getKind() == RawCommentAndCacheFlags::NoCommentInDecl)
- R = Raw;
- }
+ *OriginalDecl = nullptr;
+ return nullptr;
+}
- return RC;
+void ASTContext::cacheRawCommentForDecl(const Decl &OriginalD,
+ const RawComment &Comment) const {
+ assert(Comment.isDocumentation() || LangOpts.CommentOpts.ParseAllComments);
+ DeclRawComments.try_emplace(&OriginalD, &Comment);
+ const Decl *const CanonicalDecl = OriginalD.getCanonicalDecl();
+ RedeclChainComments.try_emplace(CanonicalDecl, &OriginalD);
+ CommentlessRedeclChains.erase(CanonicalDecl);
}
static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod,
@@ -458,6 +459,52 @@ static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod,
}
}
+void ASTContext::attachCommentsToJustParsedDecls(ArrayRef<Decl *> Decls,
+ const Preprocessor *PP) {
+ if (Comments.empty() || Decls.empty())
+ return;
+
+ // See if there are any new comments that are not attached to a decl.
+ // The location doesn't have to be precise - we care only about the file.
+ const FileID File =
+ SourceMgr.getDecomposedLoc((*Decls.begin())->getLocation()).first;
+ auto CommentsInThisFile = Comments.getCommentsInFile(File);
+ if (!CommentsInThisFile || CommentsInThisFile->empty() ||
+ CommentsInThisFile->rbegin()->second->isAttached())
+ return;
+
+ // There is at least one comment not attached to a decl.
+ // Maybe it should be attached to one of Decls?
+ //
+ // Note that this way we pick up not only comments that precede the
+ // declaration, but also comments that *follow* the declaration -- thanks to
+ // the lookahead in the lexer: we've consumed the semicolon and looked
+ // ahead through comments.
+
+ for (const Decl *D : Decls) {
+ assert(D);
+ if (D->isInvalidDecl())
+ continue;
+
+ D = &adjustDeclToTemplate(*D);
+
+ const SourceLocation DeclLoc = getDeclLocForCommentSearch(D, SourceMgr);
+
+ if (DeclLoc.isInvalid() || !DeclLoc.isFileID())
+ continue;
+
+ if (DeclRawComments.count(D) > 0)
+ continue;
+
+ if (RawComment *const DocComment =
+ getRawCommentForDeclNoCacheImpl(D, DeclLoc, *CommentsInThisFile)) {
+ cacheRawCommentForDecl(*D, *DocComment);
+ comments::FullComment *FC = DocComment->parse(*this, PP, D);
+ ParsedComments[D->getCanonicalDecl()] = FC;
+ }
+ }
+}
+
comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC,
const Decl *D) const {
auto *ThisDeclInfo = new (*this) comments::DeclInfo;
@@ -481,9 +528,9 @@ comments::FullComment *ASTContext::getLocalCommentForDeclUncached(const Decl *D)
comments::FullComment *ASTContext::getCommentForDecl(
const Decl *D,
const Preprocessor *PP) const {
- if (D->isInvalidDecl())
+ if (!D || D->isInvalidDecl())
return nullptr;
- D = adjustDeclToTemplate(D);
+ D = &adjustDeclToTemplate(*D);
const Decl *Canonical = D->getCanonicalDecl();
llvm::DenseMap<const Decl *, comments::FullComment *>::iterator Pos =
@@ -498,7 +545,7 @@ comments::FullComment *ASTContext::getCommentForDecl(
return Pos->second;
}
- const Decl *OriginalDecl;
+ const Decl *OriginalDecl = nullptr;
const RawComment *RC = getRawCommentForAnyRedecl(D, &OriginalDecl);
if (!RC) {
@@ -577,7 +624,7 @@ comments::FullComment *ASTContext::getCommentForDecl(
// should parse the comment in context of that other Decl. This is important
// because comments can contain references to parameter names which can be
// different across redeclarations.
- if (D != OriginalDecl)
+ if (D != OriginalDecl && OriginalDecl)
return getCommentForDecl(OriginalDecl, PP);
comments::FullComment *FC = RC->parse(*this, PP, D);
@@ -691,7 +738,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
cast<TemplateTemplateParmDecl>(*P)));
}
- assert(!TTP->getRequiresClause() &&
+ assert(!TTP->getTemplateParameters()->getRequiresClause() &&
"Unexpected requires-clause on template template-parameter");
Expr *const CanonRequiresClause = nullptr;
@@ -737,6 +784,13 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
llvm_unreachable("Invalid CXXABI type!");
}
+interp::Context &ASTContext::getInterpContext() {
+ if (!InterpContext) {
+ InterpContext.reset(new interp::Context(*this));
+ }
+ return *InterpContext.get();
+}
+
static const LangASMap *getAddressSpaceMap(const TargetInfo &T,
const LangOptions &LOpts) {
if (LOpts.FakeAddressSpaceMap) {
@@ -775,7 +829,8 @@ static bool isAddrSpaceMapManglingEnabled(const TargetInfo &TI,
ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
IdentifierTable &idents, SelectorTable &sels,
Builtin::Context &builtins)
- : FunctionProtoTypes(this_()), TemplateSpecializationTypes(this_()),
+ : ConstantArrayTypes(this_()), FunctionProtoTypes(this_()),
+ TemplateSpecializationTypes(this_()),
DependentTemplateSpecializationTypes(this_()),
SubstTemplateTemplateParmPacks(this_()), SourceMgr(SM), LangOpts(LOpts),
SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)),
@@ -923,7 +978,7 @@ void ASTContext::PrintStats() const {
unsigned counts[] = {
#define TYPE(Name, Parent) 0,
#define ABSTRACT_TYPE(Name, Parent)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
0 // Extra
};
@@ -943,7 +998,7 @@ void ASTContext::PrintStats() const {
TotalBytes += counts[Idx] * sizeof(Name##Type); \
++Idx;
#define ABSTRACT_TYPE(Name, Parent)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm::errs() << "Total bytes = " << TotalBytes << "\n";
@@ -1298,6 +1353,12 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
#include "clang/Basic/OpenCLExtensionTypes.def"
}
+ if (Target.hasAArch64SVETypes()) {
+#define SVE_TYPE(Name, Id, SingletonId) \
+ InitBuiltinType(SingletonId, BuiltinType::Id);
+#include "clang/Basic/AArch64SVEACLETypes.def"
+ }
+
// Builtin type for __objc_yes and __objc_no
ObjCBuiltinBoolTy = (Target.useSignedCharForObjCBool() ?
SignedCharTy : BoolTy);
@@ -1515,10 +1576,9 @@ void ASTContext::addedLocalImportDecl(ImportDecl *Import) {
/// getFloatTypeSemantics - Return the APFloat 'semantics' for the specified
/// scalar floating point type.
const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
- const auto *BT = T->getAs<BuiltinType>();
- assert(BT && "Not a floating point type!");
- switch (BT->getKind()) {
- default: llvm_unreachable("Not a floating point type!");
+ switch (T->castAs<BuiltinType>()->getKind()) {
+ default:
+ llvm_unreachable("Not a floating point type!");
case BuiltinType::Float16:
case BuiltinType::Half:
return Target->getHalfFormat();
@@ -1749,7 +1809,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
case Type::Class: \
assert(!T->isDependentType() && "should not see dependent types here"); \
return getTypeInfo(cast<Class##Type>(T)->desugar().getTypePtr());
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("Should not see dependent types");
case Type::FunctionNoProto:
@@ -1968,6 +2028,25 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
Width = Target->getPointerWidth(AS);
Align = Target->getPointerAlign(AS);
break;
+ // The SVE types are effectively target-specific. The length of an
+ // SVE_VECTOR_TYPE is only known at runtime, but it is always a multiple
+ // of 128 bits. There is one predicate bit for each vector byte, so the
+ // length of an SVE_PREDICATE_TYPE is always a multiple of 16 bits.
+ //
+ // Because the length is only known at runtime, we use a dummy value
+ // of 0 for the static length. The alignment values are those defined
+ // by the Procedure Call Standard for the Arm Architecture.
+#define SVE_VECTOR_TYPE(Name, Id, SingletonId, ElKind, ElBits, IsSigned, IsFP)\
+ case BuiltinType::Id: \
+ Width = 0; \
+ Align = 128; \
+ break;
+#define SVE_PREDICATE_TYPE(Name, Id, SingletonId, ElKind) \
+ case BuiltinType::Id: \
+ Width = 0; \
+ Align = 16; \
+ break;
+#include "clang/Basic/AArch64SVEACLETypes.def"
}
break;
case Type::ObjCObjectPointer:
@@ -2364,7 +2443,7 @@ structHasUniqueObjectRepresentations(const ASTContext &Context,
// have tail padding, so just make sure there isn't an error.
if (!isStructEmpty(Base.getType())) {
llvm::Optional<int64_t> Size = structHasUniqueObjectRepresentations(
- Context, Base.getType()->getAs<RecordType>()->getDecl());
+ Context, Base.getType()->castAs<RecordType>()->getDecl());
if (!Size)
return llvm::None;
Bases.emplace_back(Base.getType(), Size.getValue());
@@ -2455,7 +2534,7 @@ bool ASTContext::hasUniqueObjectRepresentations(QualType Ty) const {
}
if (Ty->isRecordType()) {
- const RecordDecl *Record = Ty->getAs<RecordType>()->getDecl();
+ const RecordDecl *Record = Ty->castAs<RecordType>()->getDecl();
if (Record->isInvalidDecl())
return false;
@@ -2790,7 +2869,7 @@ QualType ASTContext::getFunctionTypeWithExceptionSpec(
// Anything else must be a function type. Rebuild it with the new exception
// specification.
- const auto *Proto = Orig->getAs<FunctionProtoType>();
+ const auto *Proto = Orig->castAs<FunctionProtoType>();
return getFunctionType(
Proto->getReturnType(), Proto->getParamTypes(),
Proto->getExtProtoInfo().withExceptionSpec(ESI));
@@ -3087,31 +3166,38 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) const {
/// array of the specified element type.
QualType ASTContext::getConstantArrayType(QualType EltTy,
const llvm::APInt &ArySizeIn,
+ const Expr *SizeExpr,
ArrayType::ArraySizeModifier ASM,
unsigned IndexTypeQuals) const {
assert((EltTy->isDependentType() ||
EltTy->isIncompleteType() || EltTy->isConstantSizeType()) &&
"Constant array of VLAs is illegal!");
+ // We only need the size as part of the type if it's instantiation-dependent.
+ if (SizeExpr && !SizeExpr->isInstantiationDependent())
+ SizeExpr = nullptr;
+
// Convert the array size into a canonical width matching the pointer size for
// the target.
llvm::APInt ArySize(ArySizeIn);
ArySize = ArySize.zextOrTrunc(Target->getMaxPointerWidth());
llvm::FoldingSetNodeID ID;
- ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, IndexTypeQuals);
+ ConstantArrayType::Profile(ID, *this, EltTy, ArySize, SizeExpr, ASM,
+ IndexTypeQuals);
void *InsertPos = nullptr;
if (ConstantArrayType *ATP =
ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(ATP, 0);
- // If the element type isn't canonical or has qualifiers, this won't
- // be a canonical type either, so fill in the canonical type field.
+ // If the element type isn't canonical or has qualifiers, or the array bound
+ // is instantiation-dependent, this won't be a canonical type either, so fill
+ // in the canonical type field.
QualType Canon;
- if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) {
+ if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers() || SizeExpr) {
SplitQualType canonSplit = getCanonicalType(EltTy).split();
- Canon = getConstantArrayType(QualType(canonSplit.Ty, 0), ArySize,
+ Canon = getConstantArrayType(QualType(canonSplit.Ty, 0), ArySize, nullptr,
ASM, IndexTypeQuals);
Canon = getQualifiedType(Canon, canonSplit.Quals);
@@ -3121,8 +3207,11 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP;
}
- auto *New = new (*this,TypeAlignment)
- ConstantArrayType(EltTy, Canon, ArySize, ASM, IndexTypeQuals);
+ void *Mem = Allocate(
+ ConstantArrayType::totalSizeToAlloc<const Expr *>(SizeExpr ? 1 : 0),
+ TypeAlignment);
+ auto *New = new (Mem)
+ ConstantArrayType(EltTy, Canon, ArySize, SizeExpr, ASM, IndexTypeQuals);
ConstantArrayTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, 0);
@@ -3143,7 +3232,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("didn't desugar past all non-canonical types?");
// These types should never be variably-modified.
@@ -3219,6 +3308,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
result = getConstantArrayType(
getVariableArrayDecayedType(cat->getElementType()),
cat->getSize(),
+ cat->getSizeExpr(),
cat->getSizeModifier(),
cat->getIndexTypeCVRQualifiers());
break;
@@ -4624,8 +4714,7 @@ ASTContext::applyObjCProtocolQualifiers(QualType type,
QualType
ASTContext::getObjCTypeParamType(const ObjCTypeParamDecl *Decl,
- ArrayRef<ObjCProtocolDecl *> protocols,
- QualType Canonical) const {
+ ArrayRef<ObjCProtocolDecl *> protocols) const {
// Look in the folding set for an existing type.
llvm::FoldingSetNodeID ID;
ObjCTypeParamType::Profile(ID, Decl, protocols);
@@ -4634,16 +4723,14 @@ ASTContext::getObjCTypeParamType(const ObjCTypeParamDecl *Decl,
ObjCTypeParamTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(TypeParam, 0);
- if (Canonical.isNull()) {
- // We canonicalize to the underlying type.
- Canonical = getCanonicalType(Decl->getUnderlyingType());
- if (!protocols.empty()) {
- // Apply the protocol qualifers.
- bool hasError;
- Canonical = getCanonicalType(applyObjCProtocolQualifiers(
- Canonical, protocols, hasError, true /*allowOnPointerType*/));
- assert(!hasError && "Error when apply protocol qualifier to bound type");
- }
+ // We canonicalize to the underlying type.
+ QualType Canonical = getCanonicalType(Decl->getUnderlyingType());
+ if (!protocols.empty()) {
+ // Apply the protocol qualifers.
+ bool hasError;
+ Canonical = getCanonicalType(applyObjCProtocolQualifiers(
+ Canonical, protocols, hasError, true /*allowOnPointerType*/));
+ assert(!hasError && "Error when apply protocol qualifier to bound type");
}
unsigned size = sizeof(ObjCTypeParamType);
@@ -5114,7 +5201,7 @@ QualType ASTContext::getUnqualifiedArrayType(QualType type,
if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
return getConstantArrayType(unqualElementType, CAT->getSize(),
- CAT->getSizeModifier(), 0);
+ CAT->getSizeExpr(), CAT->getSizeModifier(), 0);
}
if (const auto *IAT = dyn_cast<IncompleteArrayType>(AT)) {
@@ -5487,6 +5574,7 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const {
if (const auto *CAT = dyn_cast<ConstantArrayType>(ATy))
return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(),
+ CAT->getSizeExpr(),
CAT->getSizeModifier(),
CAT->getIndexTypeCVRQualifiers()));
if (const auto *IAT = dyn_cast<IncompleteArrayType>(ATy))
@@ -5599,8 +5687,7 @@ static FloatingRank getFloatingRank(QualType T) {
if (const auto *CT = T->getAs<ComplexType>())
return getFloatingRank(CT->getElementType());
- assert(T->getAs<BuiltinType>() && "getFloatingRank(): not a floating type");
- switch (T->getAs<BuiltinType>()->getKind()) {
+ switch (T->castAs<BuiltinType>()->getKind()) {
default: llvm_unreachable("getFloatingRank(): not a floating type");
case BuiltinType::Float16: return Float16Rank;
case BuiltinType::Half: return HalfRank;
@@ -5977,12 +6064,10 @@ QualType ASTContext::getObjCSuperType() const {
}
void ASTContext::setCFConstantStringType(QualType T) {
- const auto *TD = T->getAs<TypedefType>();
- assert(TD && "Invalid CFConstantStringType");
+ const auto *TD = T->castAs<TypedefType>();
CFConstantStringTypeDecl = cast<TypedefDecl>(TD->getDecl());
const auto *TagType =
- CFConstantStringTypeDecl->getUnderlyingType()->getAs<RecordType>();
- assert(TagType && "Invalid CFConstantStringType");
+ CFConstantStringTypeDecl->getUnderlyingType()->castAs<RecordType>();
CFConstantStringTagDecl = TagType->getDecl();
}
@@ -6238,14 +6323,14 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
const BlockDecl *Decl = Expr->getBlockDecl();
QualType BlockTy =
- Expr->getType()->getAs<BlockPointerType>()->getPointeeType();
+ Expr->getType()->castAs<BlockPointerType>()->getPointeeType();
+ QualType BlockReturnTy = BlockTy->castAs<FunctionType>()->getReturnType();
// Encode result type.
if (getLangOpts().EncodeExtendedBlockSig)
- getObjCEncodingForMethodParameter(
- Decl::OBJC_TQ_None, BlockTy->getAs<FunctionType>()->getReturnType(), S,
- true /*Extended*/);
+ getObjCEncodingForMethodParameter(Decl::OBJC_TQ_None, BlockReturnTy, S,
+ true /*Extended*/);
else
- getObjCEncodingForType(BlockTy->getAs<FunctionType>()->getReturnType(), S);
+ getObjCEncodingForType(BlockReturnTy, S);
// 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!
@@ -6556,8 +6641,9 @@ void ASTContext::getObjCEncodingForPropertyType(QualType T,
/*Field=*/nullptr);
}
-static char getObjCEncodingForPrimitiveKind(const ASTContext *C,
- BuiltinType::Kind kind) {
+static char getObjCEncodingForPrimitiveType(const ASTContext *C,
+ const BuiltinType *BT) {
+ BuiltinType::Kind kind = BT->getKind();
switch (kind) {
case BuiltinType::Void: return 'v';
case BuiltinType::Bool: return 'B';
@@ -6617,6 +6703,17 @@ static char getObjCEncodingForPrimitiveKind(const ASTContext *C,
// FIXME: potentially need @encodes for these!
return ' ';
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
+ {
+ DiagnosticsEngine &Diags = C->getDiagnostics();
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error, "cannot yet @encode type %0");
+ Diags.Report(DiagID) << BT->getName(C->getPrintingPolicy());
+ return ' ';
+ }
+
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
@@ -6653,7 +6750,7 @@ static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) {
// The encoding of a fixed enum type matches its fixed underlying type.
const auto *BT = Enum->getIntegerType()->castAs<BuiltinType>();
- return getObjCEncodingForPrimitiveKind(C, BT->getKind());
+ return getObjCEncodingForPrimitiveType(C, BT);
}
static void EncodeBitField(const ASTContext *Ctx, std::string& S,
@@ -6693,7 +6790,7 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S,
S += ObjCEncodingForEnumType(Ctx, ET);
else {
const auto *BT = T->castAs<BuiltinType>();
- S += getObjCEncodingForPrimitiveKind(Ctx, BT->getKind());
+ S += getObjCEncodingForPrimitiveType(Ctx, BT);
}
}
S += llvm::utostr(FD->getBitWidthValue(*Ctx));
@@ -6711,7 +6808,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
if (FD && FD->isBitField())
return EncodeBitField(this, S, T, FD);
if (const auto *BT = dyn_cast<BuiltinType>(CT))
- S += getObjCEncodingForPrimitiveKind(this, BT->getKind());
+ S += getObjCEncodingForPrimitiveType(this, BT);
else
S += ObjCEncodingForEnumType(this, cast<EnumType>(CT));
return;
@@ -6760,8 +6857,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
}
} else if (Options.IsOutermostType()) {
QualType P = PointeeTy;
- while (P->getAs<PointerType>())
- P = P->getAs<PointerType>()->getPointeeType();
+ while (auto PT = P->getAs<PointerType>())
+ P = PT->getPointeeType();
if (P.isConstQualified()) {
isReadOnly = true;
S += 'r';
@@ -7033,7 +7130,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
case Type::KIND:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(KIND, BASE) \
case Type::KIND:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("@encode for dependent type!");
}
llvm_unreachable("bad type kind!");
@@ -7384,7 +7481,7 @@ static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) {
llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1);
QualType VaListTagArrayType
= Context->getConstantArrayType(VaListTagTypedefType,
- Size, ArrayType::Normal, 0);
+ Size, nullptr, ArrayType::Normal, 0);
return Context->buildImplicitTypedef(VaListTagArrayType, "__builtin_va_list");
}
@@ -7437,16 +7534,16 @@ CreateX86_64ABIBuiltinVaListDecl(const ASTContext *Context) {
// typedef struct __va_list_tag __builtin_va_list[1];
llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1);
- QualType VaListTagArrayType =
- Context->getConstantArrayType(VaListTagType, Size, ArrayType::Normal, 0);
+ QualType VaListTagArrayType = Context->getConstantArrayType(
+ VaListTagType, Size, nullptr, ArrayType::Normal, 0);
return Context->buildImplicitTypedef(VaListTagArrayType, "__builtin_va_list");
}
static TypedefDecl *CreatePNaClABIBuiltinVaListDecl(const ASTContext *Context) {
// typedef int __builtin_va_list[4];
llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 4);
- QualType IntArrayType =
- Context->getConstantArrayType(Context->IntTy, Size, ArrayType::Normal, 0);
+ QualType IntArrayType = Context->getConstantArrayType(
+ Context->IntTy, Size, nullptr, ArrayType::Normal, 0);
return Context->buildImplicitTypedef(IntArrayType, "__builtin_va_list");
}
@@ -7540,8 +7637,8 @@ CreateSystemZBuiltinVaListDecl(const ASTContext *Context) {
// typedef __va_list_tag __builtin_va_list[1];
llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1);
- QualType VaListTagArrayType =
- Context->getConstantArrayType(VaListTagType, Size, ArrayType::Normal, 0);
+ QualType VaListTagArrayType = Context->getConstantArrayType(
+ VaListTagType, Size, nullptr, ArrayType::Normal, 0);
return Context->buildImplicitTypedef(VaListTagArrayType, "__builtin_va_list");
}
@@ -7816,7 +7913,7 @@ Qualifiers::GC ASTContext::getObjCGCAttrKind(QualType Ty) const {
if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType())
return Qualifiers::Strong;
else if (Ty->isPointerType())
- return getObjCGCAttrKind(Ty->getAs<PointerType>()->getPointeeType());
+ return getObjCGCAttrKind(Ty->castAs<PointerType>()->getPointeeType());
} else {
// It's not valid to set GC attributes on anything that isn't a
// pointer.
@@ -7853,8 +7950,8 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec,
// Treat Neon vector types and most AltiVec vector types as if they are the
// equivalent GCC vector types.
- const auto *First = FirstVec->getAs<VectorType>();
- const auto *Second = SecondVec->getAs<VectorType>();
+ const auto *First = FirstVec->castAs<VectorType>();
+ const auto *Second = SecondVec->castAs<VectorType>();
if (First->getNumElements() == Second->getNumElements() &&
hasSameType(First->getElementType(), Second->getElementType()) &&
First->getVectorKind() != VectorType::AltiVecPixel &&
@@ -7866,6 +7963,28 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec,
return false;
}
+bool ASTContext::hasDirectOwnershipQualifier(QualType Ty) const {
+ while (true) {
+ // __strong id
+ if (const AttributedType *Attr = dyn_cast<AttributedType>(Ty)) {
+ if (Attr->getAttrKind() == attr::ObjCOwnership)
+ return true;
+
+ Ty = Attr->getModifiedType();
+
+ // X *__strong (...)
+ } else if (const ParenType *Paren = dyn_cast<ParenType>(Ty)) {
+ Ty = Paren->getInnerType();
+
+ // 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;
+ }
+ }
+}
+
//===----------------------------------------------------------------------===//
// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's.
//===----------------------------------------------------------------------===//
@@ -7885,15 +8004,11 @@ ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
/// ObjCQualifiedClassTypesAreCompatible - compare Class<pr,...> and
/// Class<pr1, ...>.
-bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs,
- QualType rhs) {
- const auto *lhsQID = lhs->getAs<ObjCObjectPointerType>();
- const auto *rhsOPT = rhs->getAs<ObjCObjectPointerType>();
- assert((lhsQID && rhsOPT) && "ObjCQualifiedClassTypesAreCompatible");
-
- for (auto *lhsProto : lhsQID->quals()) {
+bool ASTContext::ObjCQualifiedClassTypesAreCompatible(
+ const ObjCObjectPointerType *lhs, const ObjCObjectPointerType *rhs) {
+ for (auto *lhsProto : lhs->quals()) {
bool match = false;
- for (auto *rhsProto : rhsOPT->quals()) {
+ for (auto *rhsProto : rhs->quals()) {
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto)) {
match = true;
break;
@@ -7907,26 +8022,24 @@ bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs,
/// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an
/// ObjCQualifiedIDType.
-bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
- bool compare) {
- // Allow id<P..> and an 'id' or void* type in all cases.
- if (lhs->isVoidPointerType() ||
- lhs->isObjCIdType() || lhs->isObjCClassType())
- return true;
- else if (rhs->isVoidPointerType() ||
- rhs->isObjCIdType() || rhs->isObjCClassType())
+bool ASTContext::ObjCQualifiedIdTypesAreCompatible(
+ const ObjCObjectPointerType *lhs, const ObjCObjectPointerType *rhs,
+ bool compare) {
+ // Allow id<P..> and an 'id' in all cases.
+ if (lhs->isObjCIdType() || rhs->isObjCIdType())
return true;
- if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) {
- const auto *rhsOPT = rhs->getAs<ObjCObjectPointerType>();
-
- if (!rhsOPT) return false;
+ // Don't allow id<P..> to convert to Class or Class<P..> in either direction.
+ if (lhs->isObjCClassType() || lhs->isObjCQualifiedClassType() ||
+ rhs->isObjCClassType() || rhs->isObjCQualifiedClassType())
+ return false;
- if (rhsOPT->qual_empty()) {
+ if (lhs->isObjCQualifiedIdType()) {
+ if (rhs->qual_empty()) {
// If the RHS is a unqualified interface pointer "NSString*",
// make sure we check the class hierarchy.
- if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
- for (auto *I : lhsQID->quals()) {
+ if (ObjCInterfaceDecl *rhsID = rhs->getInterfaceDecl()) {
+ for (auto *I : lhs->quals()) {
// when comparing an id<P> on lhs with a static type on rhs,
// see if static class implements all of id's protocols, directly or
// through its super class and categories.
@@ -7938,13 +8051,13 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
return true;
}
// Both the right and left sides have qualifiers.
- for (auto *lhsProto : lhsQID->quals()) {
+ for (auto *lhsProto : lhs->quals()) {
bool match = false;
// when comparing an id<P> on lhs with a static type on rhs,
// see if static class implements all of id's protocols, directly or
// through its super class and categories.
- for (auto *rhsProto : rhsOPT->quals()) {
+ for (auto *rhsProto : rhs->quals()) {
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
(compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
match = true;
@@ -7953,8 +8066,8 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
}
// If the RHS is a qualified interface pointer "NSString<P>*",
// make sure we check the class hierarchy.
- if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
- for (auto *I : lhsQID->quals()) {
+ if (ObjCInterfaceDecl *rhsID = rhs->getInterfaceDecl()) {
+ for (auto *I : lhs->quals()) {
// when comparing an id<P> on lhs with a static type on rhs,
// see if static class implements all of id's protocols, directly or
// through its super class and categories.
@@ -7971,13 +8084,11 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
return true;
}
- const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType();
- assert(rhsQID && "One of the LHS/RHS should be id<x>");
+ assert(rhs->isObjCQualifiedIdType() && "One of the LHS/RHS should be id<x>");
- if (const ObjCObjectPointerType *lhsOPT =
- lhs->getAsObjCInterfacePointerType()) {
+ if (lhs->getInterfaceType()) {
// If both the right and left sides have qualifiers.
- for (auto *lhsProto : lhsOPT->quals()) {
+ for (auto *lhsProto : lhs->quals()) {
bool match = false;
// when comparing an id<P> on rhs with a static type on lhs,
@@ -7985,7 +8096,7 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
// through its super class and categories.
// First, lhs protocols in the qualifier list must be found, direct
// or indirect in rhs's qualifier list or it is a mismatch.
- for (auto *rhsProto : rhsQID->quals()) {
+ for (auto *rhsProto : rhs->quals()) {
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
(compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
match = true;
@@ -7998,17 +8109,17 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
// Static class's protocols, or its super class or category protocols
// must be found, direct or indirect in rhs's qualifier list or it is a mismatch.
- if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) {
+ if (ObjCInterfaceDecl *lhsID = lhs->getInterfaceDecl()) {
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols;
CollectInheritedProtocols(lhsID, LHSInheritedProtocols);
// This is rather dubious but matches gcc's behavior. If lhs has
// no type qualifier and its class has no static protocol(s)
// assume that it is mismatch.
- if (LHSInheritedProtocols.empty() && lhsOPT->qual_empty())
+ if (LHSInheritedProtocols.empty() && lhs->qual_empty())
return false;
for (auto *lhsProto : LHSInheritedProtocols) {
bool match = false;
- for (auto *rhsProto : rhsQID->quals()) {
+ for (auto *rhsProto : rhs->quals()) {
if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
(compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
match = true;
@@ -8032,9 +8143,8 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
const ObjCObjectType* LHS = LHSOPT->getObjectType();
const ObjCObjectType* RHS = RHSOPT->getObjectType();
- // If either type represents the built-in 'id' or 'Class' types, return true.
- if (LHS->isObjCUnqualifiedIdOrClass() ||
- RHS->isObjCUnqualifiedIdOrClass())
+ // If either type represents the built-in 'id' type, return true.
+ if (LHS->isObjCUnqualifiedId() || RHS->isObjCUnqualifiedId())
return true;
// Function object that propagates a successful result or handles
@@ -8052,15 +8162,20 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT,
LHSOPT->stripObjCKindOfTypeAndQuals(*this));
};
+ // Casts from or to id<P> are allowed when the other side has compatible
+ // protocols.
if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId()) {
- return finish(ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
- QualType(RHSOPT,0),
- false));
+ return finish(ObjCQualifiedIdTypesAreCompatible(LHSOPT, RHSOPT, false));
}
+ // Verify protocol compatibility for casts from Class<P1> to Class<P2>.
if (LHS->isObjCQualifiedClass() && RHS->isObjCQualifiedClass()) {
- return finish(ObjCQualifiedClassTypesAreCompatible(QualType(LHSOPT,0),
- QualType(RHSOPT,0)));
+ return finish(ObjCQualifiedClassTypesAreCompatible(LHSOPT, RHSOPT));
+ }
+
+ // Casts from Class to Class<Foo>, or vice-versa, are allowed.
+ if (LHS->isObjCClass() && RHS->isObjCClass()) {
+ return true;
}
// If we have 2 user-defined types, fall into that path.
@@ -8108,9 +8223,9 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer(
}
if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType())
- return finish(ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0),
- QualType(RHSOPT,0),
- false));
+ return finish(ObjCQualifiedIdTypesAreCompatible(
+ (BlockReturnType ? LHSOPT : RHSOPT),
+ (BlockReturnType ? RHSOPT : LHSOPT), false));
const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType();
const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType();
@@ -8834,7 +8949,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("Non-canonical and dependent types shouldn't get here");
case Type::Auto:
@@ -8854,8 +8969,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
case Type::Pointer:
{
// Merge two pointer types, while trying to preserve typedef info
- QualType LHSPointee = LHS->getAs<PointerType>()->getPointeeType();
- QualType RHSPointee = RHS->getAs<PointerType>()->getPointeeType();
+ QualType LHSPointee = LHS->castAs<PointerType>()->getPointeeType();
+ QualType RHSPointee = RHS->castAs<PointerType>()->getPointeeType();
if (Unqualified) {
LHSPointee = LHSPointee.getUnqualifiedType();
RHSPointee = RHSPointee.getUnqualifiedType();
@@ -8873,8 +8988,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
case Type::BlockPointer:
{
// Merge two block pointer types, while trying to preserve typedef info
- QualType LHSPointee = LHS->getAs<BlockPointerType>()->getPointeeType();
- QualType RHSPointee = RHS->getAs<BlockPointerType>()->getPointeeType();
+ QualType LHSPointee = LHS->castAs<BlockPointerType>()->getPointeeType();
+ QualType RHSPointee = RHS->castAs<BlockPointerType>()->getPointeeType();
if (Unqualified) {
LHSPointee = LHSPointee.getUnqualifiedType();
RHSPointee = RHSPointee.getUnqualifiedType();
@@ -8906,8 +9021,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
case Type::Atomic:
{
// Merge two pointer types, while trying to preserve typedef info
- QualType LHSValue = LHS->getAs<AtomicType>()->getValueType();
- QualType RHSValue = RHS->getAs<AtomicType>()->getValueType();
+ QualType LHSValue = LHS->castAs<AtomicType>()->getValueType();
+ QualType RHSValue = RHS->castAs<AtomicType>()->getValueType();
if (Unqualified) {
LHSValue = LHSValue.getUnqualifiedType();
RHSValue = RHSValue.getUnqualifiedType();
@@ -8975,10 +9090,14 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
return LHS;
if (RCAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType))
return RHS;
- if (LCAT) return getConstantArrayType(ResultType, LCAT->getSize(),
- ArrayType::ArraySizeModifier(), 0);
- if (RCAT) return getConstantArrayType(ResultType, RCAT->getSize(),
- ArrayType::ArraySizeModifier(), 0);
+ if (LCAT)
+ return getConstantArrayType(ResultType, LCAT->getSize(),
+ LCAT->getSizeExpr(),
+ ArrayType::ArraySizeModifier(), 0);
+ if (RCAT)
+ return getConstantArrayType(ResultType, RCAT->getSize(),
+ RCAT->getSizeExpr(),
+ ArrayType::ArraySizeModifier(), 0);
if (LVAT && getCanonicalType(LHSElem) == getCanonicalType(ResultType))
return LHS;
if (RVAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType))
@@ -9013,34 +9132,30 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
return {};
case Type::Vector:
// FIXME: The merged type should be an ExtVector!
- if (areCompatVectorTypes(LHSCan->getAs<VectorType>(),
- RHSCan->getAs<VectorType>()))
+ if (areCompatVectorTypes(LHSCan->castAs<VectorType>(),
+ RHSCan->castAs<VectorType>()))
return LHS;
return {};
case Type::ObjCObject: {
// Check if the types are assignment compatible.
// FIXME: This should be type compatibility, e.g. whether
// "LHS x; RHS x;" at global scope is legal.
- const auto *LHSIface = LHS->getAs<ObjCObjectType>();
- const auto *RHSIface = RHS->getAs<ObjCObjectType>();
- if (canAssignObjCInterfaces(LHSIface, RHSIface))
+ if (canAssignObjCInterfaces(LHS->castAs<ObjCObjectType>(),
+ RHS->castAs<ObjCObjectType>()))
return LHS;
-
return {};
}
case Type::ObjCObjectPointer:
if (OfBlockPointer) {
if (canAssignObjCInterfacesInBlockPointer(
- LHS->getAs<ObjCObjectPointerType>(),
- RHS->getAs<ObjCObjectPointerType>(),
- BlockReturnType))
+ LHS->castAs<ObjCObjectPointerType>(),
+ RHS->castAs<ObjCObjectPointerType>(), BlockReturnType))
return LHS;
return {};
}
- if (canAssignObjCInterfaces(LHS->getAs<ObjCObjectPointerType>(),
- RHS->getAs<ObjCObjectPointerType>()))
+ if (canAssignObjCInterfaces(LHS->castAs<ObjCObjectPointerType>(),
+ RHS->castAs<ObjCObjectPointerType>()))
return LHS;
-
return {};
case Type::Pipe:
assert(LHS != RHS &&
@@ -9125,7 +9240,7 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
if (ResReturnType == NewReturnType || ResReturnType == OldReturnType) {
// id foo(); ... __strong id foo(); or: __strong id foo(); ... id foo();
// In either case, use OldReturnType to build the new function type.
- const auto *F = LHS->getAs<FunctionType>();
+ const auto *F = LHS->castAs<FunctionType>();
if (const auto *FPT = cast<FunctionProtoType>(F)) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = getFunctionExtInfo(LHS);
@@ -9166,8 +9281,8 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
}
if (LHSCan->isObjCObjectPointerType() && RHSCan->isObjCObjectPointerType()) {
- QualType LHSBaseQT = LHS->getAs<ObjCObjectPointerType>()->getPointeeType();
- QualType RHSBaseQT = RHS->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType LHSBaseQT = LHS->castAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType RHSBaseQT = RHS->castAs<ObjCObjectPointerType>()->getPointeeType();
QualType ResQT = mergeObjCGCQualifiers(LHSBaseQT, RHSBaseQT);
if (ResQT == LHSBaseQT)
return LHS;
@@ -9203,9 +9318,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
if (const auto *ETy = T->getAs<EnumType>())
T = ETy->getDecl()->getIntegerType();
- const auto *BTy = T->getAs<BuiltinType>();
- assert(BTy && "Unexpected signed integer or fixed point type");
- switch (BTy->getKind()) {
+ switch (T->castAs<BuiltinType>()->getKind()) {
case BuiltinType::Char_S:
case BuiltinType::SChar:
return UnsignedCharTy;
@@ -9860,7 +9973,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
return !D->getDeclContext()->isDependentContext();
else if (isa<OMPAllocateDecl>(D))
return !D->getDeclContext()->isDependentContext();
- else if (isa<OMPDeclareReductionDecl>(D))
+ else if (isa<OMPDeclareReductionDecl>(D) || isa<OMPDeclareMapperDecl>(D))
return !D->getDeclContext()->isDependentContext();
else if (isa<ImportDecl>(D))
return true;
@@ -9963,7 +10076,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
return false;
// Variables that have destruction with side-effects are required.
- if (VD->getType().isDestructedType())
+ if (VD->needsDestruction(*this))
return true;
// Variables that have initialization with side-effects are required.
@@ -10035,7 +10148,7 @@ CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic,
break;
}
}
- return Target->getDefaultCallingConv(TargetInfo::CCMT_Unknown);
+ return Target->getDefaultCallingConv();
}
bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {
@@ -10153,6 +10266,16 @@ ASTContext::getManglingNumberContext(const DeclContext *DC) {
return *MCtx;
}
+MangleNumberingContext &
+ASTContext::getManglingNumberContext(NeedExtraManglingDecl_t, const Decl *D) {
+ assert(LangOpts.CPlusPlus); // We don't need mangling numbers for plain C.
+ std::unique_ptr<MangleNumberingContext> &MCtx =
+ ExtraMangleNumberingContexts[D];
+ if (!MCtx)
+ MCtx = createMangleNumberingContext();
+ return *MCtx;
+}
+
std::unique_ptr<MangleNumberingContext>
ASTContext::createMangleNumberingContext() const {
return ABI->createMangleNumberingContext();
@@ -10226,7 +10349,7 @@ QualType ASTContext::getStringLiteralArrayType(QualType EltTy,
// Get an array type for the string, according to C99 6.4.5. This includes
// the null terminator character.
- return getConstantArrayType(EltTy, llvm::APInt(32, Length + 1),
+ return getConstantArrayType(EltTy, llvm::APInt(32, Length + 1), nullptr,
ArrayType::Normal, /*IndexTypeQuals*/ 0);
}
@@ -10389,7 +10512,7 @@ ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) {
if (!Parents)
// We build the parent map for the traversal scope (usually whole TU), as
// hasAncestor can escape any subtree.
- Parents = llvm::make_unique<ParentMap>(*this);
+ Parents = std::make_unique<ParentMap>(*this);
return Parents->getParents(Node);
}
@@ -10446,8 +10569,7 @@ QualType ASTContext::getCorrespondingSaturatedType(QualType Ty) const {
if (Ty->isSaturatedFixedPointType()) return Ty;
- const auto &BT = Ty->getAs<BuiltinType>();
- switch (BT->getKind()) {
+ switch (Ty->castAs<BuiltinType>()->getKind()) {
default:
llvm_unreachable("Not a fixed point type!");
case BuiltinType::ShortAccum:
@@ -10499,9 +10621,8 @@ clang::LazyGenerationalUpdatePtr<
unsigned char ASTContext::getFixedPointScale(QualType Ty) const {
assert(Ty->isFixedPointType());
- const auto *BT = Ty->getAs<BuiltinType>();
const TargetInfo &Target = getTargetInfo();
- switch (BT->getKind()) {
+ switch (Ty->castAs<BuiltinType>()->getKind()) {
default:
llvm_unreachable("Not a fixed point type!");
case BuiltinType::ShortAccum:
@@ -10546,9 +10667,8 @@ unsigned char ASTContext::getFixedPointScale(QualType Ty) const {
unsigned char ASTContext::getFixedPointIBits(QualType Ty) const {
assert(Ty->isFixedPointType());
- const auto *BT = Ty->getAs<BuiltinType>();
const TargetInfo &Target = getTargetInfo();
- switch (BT->getKind()) {
+ switch (Ty->castAs<BuiltinType>()->getKind()) {
default:
llvm_unreachable("Not a fixed point type!");
case BuiltinType::ShortAccum:
@@ -10613,9 +10733,8 @@ APFixedPoint ASTContext::getFixedPointMin(QualType Ty) const {
QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const {
assert(Ty->isUnsignedFixedPointType() &&
"Expected unsigned fixed point type");
- const auto *BTy = Ty->getAs<BuiltinType>();
- switch (BTy->getKind()) {
+ switch (Ty->castAs<BuiltinType>()->getKind()) {
case BuiltinType::UShortAccum:
return ShortAccumTy;
case BuiltinType::UAccum:
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 15df86585294..30985441031d 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -154,7 +154,7 @@ Underlying = CTy->desugar(); \
} \
break; \
}
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
// If it wasn't sugared, we're done.
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 9d5dd84161de..54acca7dc62c 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -80,6 +80,7 @@ namespace clang {
using ExpectedExpr = llvm::Expected<Expr *>;
using ExpectedDecl = llvm::Expected<Decl *>;
using ExpectedSLoc = llvm::Expected<SourceLocation>;
+ using ExpectedName = llvm::Expected<DeclarationName>;
std::string ImportError::toString() const {
// FIXME: Improve error texts.
@@ -426,6 +427,9 @@ namespace clang {
Error ImportFunctionDeclBody(FunctionDecl *FromFD, FunctionDecl *ToFD);
+ Error ImportDefaultArgOfParmVarDecl(const ParmVarDecl *FromParam,
+ ParmVarDecl *ToParam);
+
template <typename T>
bool hasSameVisibilityContext(T *Found, T *From);
@@ -635,7 +639,8 @@ namespace clang {
return ImportArrayChecked(InContainer.begin(), InContainer.end(), Obegin);
}
- void ImportOverrides(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod);
+ Error ImportOverriddenMethods(CXXMethodDecl *ToMethod,
+ CXXMethodDecl *FromMethod);
Expected<FunctionDecl *> FindFunctionTemplateSpecialization(
FunctionDecl *FromFD);
@@ -927,6 +932,27 @@ Expected<LambdaCapture> ASTNodeImporter::import(const LambdaCapture &From) {
EllipsisLoc);
}
+template <typename T>
+bool ASTNodeImporter::hasSameVisibilityContext(T *Found, T *From) {
+ if (From->hasExternalFormalLinkage())
+ return Found->hasExternalFormalLinkage();
+ if (Importer.GetFromTU(Found) != From->getTranslationUnitDecl())
+ return false;
+ if (From->isInAnonymousNamespace())
+ return Found->isInAnonymousNamespace();
+ else
+ return !Found->isInAnonymousNamespace() &&
+ !Found->hasExternalFormalLinkage();
+}
+
+template <>
+bool ASTNodeImporter::hasSameVisibilityContext(TypedefNameDecl *Found,
+ TypedefNameDecl *From) {
+ if (From->isInAnonymousNamespace() && Found->isInAnonymousNamespace())
+ return Importer.GetFromTU(Found) == From->getTranslationUnitDecl();
+ return From->isInAnonymousNamespace() == Found->isInAnonymousNamespace();
+}
+
} // namespace clang
//----------------------------------------------------------------------------
@@ -959,6 +985,10 @@ ExpectedType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) {
case BuiltinType::Id: \
return Importer.getToContext().Id##Ty;
#include "clang/Basic/OpenCLExtensionTypes.def"
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id: \
+ return Importer.getToContext().SingletonId;
+#include "clang/Basic/AArch64SVEACLETypes.def"
#define SHARED_SINGLETON_TYPE(Expansion)
#define BUILTIN_TYPE(Id, SingletonId) \
case BuiltinType::Id: return Importer.getToContext().SingletonId;
@@ -1068,14 +1098,16 @@ ASTNodeImporter::VisitMemberPointerType(const MemberPointerType *T) {
ExpectedType
ASTNodeImporter::VisitConstantArrayType(const ConstantArrayType *T) {
- ExpectedType ToElementTypeOrErr = import(T->getElementType());
- if (!ToElementTypeOrErr)
- return ToElementTypeOrErr.takeError();
+ QualType ToElementType;
+ const Expr *ToSizeExpr;
+ if (auto Imp = importSeq(T->getElementType(), T->getSizeExpr()))
+ std::tie(ToElementType, ToSizeExpr) = *Imp;
+ else
+ return Imp.takeError();
- return Importer.getToContext().getConstantArrayType(*ToElementTypeOrErr,
- T->getSize(),
- T->getSizeModifier(),
- T->getIndexTypeCVRQualifiers());
+ return Importer.getToContext().getConstantArrayType(
+ ToElementType, T->getSize(), ToSizeExpr, T->getSizeModifier(),
+ T->getIndexTypeCVRQualifiers());
}
ExpectedType
@@ -1645,7 +1677,6 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
bool AccumulateChildErrors = isa<TagDecl>(FromDC);
Error ChildErrors = Error::success();
- llvm::SmallVector<Decl *, 8> ImportedDecls;
for (auto *From : FromDC->decls()) {
ExpectedDecl ImportedOrErr = import(From);
if (!ImportedOrErr) {
@@ -1657,6 +1688,59 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
}
}
+ // We reorder declarations in RecordDecls because they may have another order
+ // in the "to" context than they have in the "from" context. This may happen
+ // e.g when we import a class like this:
+ // struct declToImport {
+ // int a = c + b;
+ // int b = 1;
+ // int c = 2;
+ // };
+ // During the import of `a` we import first the dependencies in sequence,
+ // thus the order would be `c`, `b`, `a`. We will get the normal order by
+ // first removing the already imported members and then adding them in the
+ // order as they apper in the "from" context.
+ //
+ // Keeping field order is vital because it determines structure layout.
+ //
+ // Here and below, we cannot call field_begin() method and its callers on
+ // ToDC if it has an external storage. Calling field_begin() will
+ // automatically load all the fields by calling
+ // LoadFieldsFromExternalStorage(). LoadFieldsFromExternalStorage() would
+ // call ASTImporter::Import(). This is because the ExternalASTSource
+ // interface in LLDB is implemented by the means of the ASTImporter. However,
+ // calling an import at this point would result in an uncontrolled import, we
+ // must avoid that.
+ const auto *FromRD = dyn_cast<RecordDecl>(FromDC);
+ if (!FromRD)
+ return ChildErrors;
+
+ auto ToDCOrErr = Importer.ImportContext(FromDC);
+ if (!ToDCOrErr) {
+ consumeError(std::move(ChildErrors));
+ return ToDCOrErr.takeError();
+ }
+
+ DeclContext *ToDC = *ToDCOrErr;
+ // Remove all declarations, which may be in wrong order in the
+ // lexical DeclContext and then add them in the proper order.
+ for (auto *D : FromRD->decls()) {
+ if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D) || isa<FriendDecl>(D)) {
+ assert(D && "DC contains a null decl");
+ Decl *ToD = Importer.GetAlreadyImportedOrNull(D);
+ // Remove only the decls which we successfully imported.
+ if (ToD) {
+ assert(ToDC == ToD->getLexicalDeclContext() && ToDC->containsDecl(ToD));
+ // Remove the decl from its wrong place in the linked list.
+ ToDC->removeDecl(ToD);
+ // Add the decl to the end of the linked list.
+ // This time it will be at the proper place because the enclosing for
+ // loop iterates in the original (good) order of the decls.
+ ToDC->addDeclInternal(ToD);
+ }
+ }
+ }
+
return ChildErrors;
}
@@ -1752,71 +1836,10 @@ Error ASTNodeImporter::ImportDefinition(
struct CXXRecordDecl::DefinitionData &ToData = ToCXX->data();
struct CXXRecordDecl::DefinitionData &FromData = FromCXX->data();
- ToData.UserDeclaredConstructor = FromData.UserDeclaredConstructor;
- ToData.UserDeclaredSpecialMembers = FromData.UserDeclaredSpecialMembers;
- 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.IsCXX11StandardLayout = FromData.IsCXX11StandardLayout;
- ToData.HasBasesWithFields = FromData.HasBasesWithFields;
- ToData.HasBasesWithNonStaticDataMembers =
- FromData.HasBasesWithNonStaticDataMembers;
- ToData.HasPrivateFields = FromData.HasPrivateFields;
- ToData.HasProtectedFields = FromData.HasProtectedFields;
- ToData.HasPublicFields = FromData.HasPublicFields;
- ToData.HasMutableFields = FromData.HasMutableFields;
- ToData.HasVariantMembers = FromData.HasVariantMembers;
- ToData.HasOnlyCMembers = FromData.HasOnlyCMembers;
- ToData.HasInClassInitializer = FromData.HasInClassInitializer;
- ToData.HasUninitializedReferenceMember
- = FromData.HasUninitializedReferenceMember;
- ToData.HasUninitializedFields = FromData.HasUninitializedFields;
- ToData.HasInheritedConstructor = FromData.HasInheritedConstructor;
- ToData.HasInheritedAssignment = FromData.HasInheritedAssignment;
- ToData.NeedOverloadResolutionForCopyConstructor
- = FromData.NeedOverloadResolutionForCopyConstructor;
- ToData.NeedOverloadResolutionForMoveConstructor
- = FromData.NeedOverloadResolutionForMoveConstructor;
- ToData.NeedOverloadResolutionForMoveAssignment
- = FromData.NeedOverloadResolutionForMoveAssignment;
- ToData.NeedOverloadResolutionForDestructor
- = FromData.NeedOverloadResolutionForDestructor;
- ToData.DefaultedCopyConstructorIsDeleted
- = FromData.DefaultedCopyConstructorIsDeleted;
- ToData.DefaultedMoveConstructorIsDeleted
- = FromData.DefaultedMoveConstructorIsDeleted;
- ToData.DefaultedMoveAssignmentIsDeleted
- = FromData.DefaultedMoveAssignmentIsDeleted;
- ToData.DefaultedDestructorIsDeleted = FromData.DefaultedDestructorIsDeleted;
- ToData.HasTrivialSpecialMembers = FromData.HasTrivialSpecialMembers;
- ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor;
- ToData.HasConstexprNonCopyMoveConstructor
- = FromData.HasConstexprNonCopyMoveConstructor;
- ToData.HasDefaultedDefaultConstructor
- = FromData.HasDefaultedDefaultConstructor;
- ToData.DefaultedDefaultConstructorIsConstexpr
- = FromData.DefaultedDefaultConstructorIsConstexpr;
- ToData.HasConstexprDefaultConstructor
- = FromData.HasConstexprDefaultConstructor;
- ToData.HasNonLiteralTypeFieldsOrBases
- = FromData.HasNonLiteralTypeFieldsOrBases;
- // ComputedVisibleConversions not imported.
- ToData.UserProvidedDefaultConstructor
- = FromData.UserProvidedDefaultConstructor;
- ToData.DeclaredSpecialMembers = FromData.DeclaredSpecialMembers;
- ToData.ImplicitCopyConstructorCanHaveConstParamForVBase
- = FromData.ImplicitCopyConstructorCanHaveConstParamForVBase;
- ToData.ImplicitCopyConstructorCanHaveConstParamForNonVBase
- = FromData.ImplicitCopyConstructorCanHaveConstParamForNonVBase;
- ToData.ImplicitCopyAssignmentHasConstParam
- = FromData.ImplicitCopyAssignmentHasConstParam;
- ToData.HasDeclaredCopyConstructorWithConstParam
- = FromData.HasDeclaredCopyConstructorWithConstParam;
- ToData.HasDeclaredCopyAssignmentWithConstParam
- = FromData.HasDeclaredCopyAssignmentWithConstParam;
+
+ #define FIELD(Name, Width, Merge) \
+ ToData.Name = FromData.Name;
+ #include "clang/AST/CXXRecordDeclDefinitionBits.def"
// Copy over the data stored in RecordDeclBits
ToCXX->setArgPassingRestrictions(FromCXX->getArgPassingRestrictions());
@@ -2188,11 +2211,13 @@ ExpectedDecl ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Namespace,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, Decl::IDNS_Namespace, ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
@@ -2281,6 +2306,9 @@ ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
// If this typedef is not in block scope, determine whether we've
// seen a typedef with the same name (that we can merge with) or any
// other entity by that name (which name lookup could conflict with).
+ // Note: Repeated typedefs are not valid in C99:
+ // 'typedef int T; typedef int T;' is invalid
+ // We do not care about this now.
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
@@ -2289,6 +2317,9 @@ ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
if (!FoundDecl->isInIdentifierNamespace(IDNS))
continue;
if (auto *FoundTypedef = dyn_cast<TypedefNameDecl>(FoundDecl)) {
+ if (!hasSameVisibilityContext(FoundTypedef, D))
+ continue;
+
QualType FromUT = D->getUnderlyingType();
QualType FoundUT = FoundTypedef->getUnderlyingType();
if (Importer.IsStructurallyEquivalent(FromUT, FoundUT)) {
@@ -2296,21 +2327,21 @@ ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
// already have a complete underlying type then return with that.
if (!FromUT->isIncompleteType() && !FoundUT->isIncompleteType())
return Importer.MapImported(D, FoundTypedef);
+ // FIXME Handle redecl chain. When you do that make consistent changes
+ // in ASTImporterLookupTable too.
+ } else {
+ ConflictingDecls.push_back(FoundDecl);
}
- // FIXME Handle redecl chain. When you do that make consistent changes
- // in ASTImporterLookupTable too.
- break;
}
-
- ConflictingDecls.push_back(FoundDecl);
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, IDNS,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
@@ -2383,11 +2414,12 @@ ASTNodeImporter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, IDNS,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
@@ -2491,17 +2523,18 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
continue;
if (IsStructuralMatch(D, FoundEnum))
return Importer.MapImported(D, FoundEnum);
+ ConflictingDecls.push_back(FoundDecl);
}
-
- ConflictingDecls.push_back(FoundDecl);
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(SearchName, DC, IDNS,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ SearchName, DC, IDNS, ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
@@ -2546,10 +2579,10 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
}
// Import the major distinguishing characteristics of this record.
- DeclContext *DC, *LexicalDC;
+ DeclContext *DC = nullptr, *LexicalDC = nullptr;
DeclarationName Name;
SourceLocation Loc;
- NamedDecl *ToD;
+ NamedDecl *ToD = nullptr;
if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc))
return std::move(Err);
if (ToD)
@@ -2568,7 +2601,7 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
// We may already have a record of the same name; try to find and match it.
RecordDecl *PrevDecl = nullptr;
- if (!DC->isFunctionOrMethod()) {
+ if (!DC->isFunctionOrMethod() && !D->isLambda()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
auto FoundDecls =
Importer.findDeclsInToCtx(DC, SearchName);
@@ -2626,17 +2659,18 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
PrevDecl = FoundRecord->getMostRecentDecl();
break;
}
- }
-
- ConflictingDecls.push_back(FoundDecl);
+ ConflictingDecls.push_back(FoundDecl);
+ } // kind is RecordDecl
} // for
if (!ConflictingDecls.empty() && SearchName) {
- Name = Importer.HandleNameConflict(SearchName, DC, IDNS,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ SearchName, DC, IDNS, ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
@@ -2660,7 +2694,8 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
ExpectedDecl CDeclOrErr = import(DCXX->getLambdaContextDecl());
if (!CDeclOrErr)
return CDeclOrErr.takeError();
- D2CXX->setLambdaMangling(DCXX->getLambdaManglingNumber(), *CDeclOrErr);
+ D2CXX->setLambdaMangling(DCXX->getLambdaManglingNumber(), *CDeclOrErr,
+ DCXX->hasKnownLambdaInternalLinkage());
} else if (DCXX->isInjectedClassName()) {
// We have to be careful to do a similar dance to the one in
// Sema::ActOnStartCXXMemberDeclarations
@@ -2795,17 +2830,17 @@ ExpectedDecl ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
if (auto *FoundEnumConstant = dyn_cast<EnumConstantDecl>(FoundDecl)) {
if (IsStructuralMatch(D, FoundEnumConstant))
return Importer.MapImported(D, FoundEnumConstant);
+ ConflictingDecls.push_back(FoundDecl);
}
-
- ConflictingDecls.push_back(FoundDecl);
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, IDNS,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
@@ -2956,19 +2991,6 @@ Error ASTNodeImporter::ImportFunctionDeclBody(FunctionDecl *FromFD,
return Error::success();
}
-template <typename T>
-bool ASTNodeImporter::hasSameVisibilityContext(T *Found, T *From) {
- if (From->hasExternalFormalLinkage())
- return Found->hasExternalFormalLinkage();
- if (Importer.GetFromTU(Found) != From->getTranslationUnitDecl())
- return false;
- if (From->isInAnonymousNamespace())
- return Found->isInAnonymousNamespace();
- else
- return !Found->isInAnonymousNamespace() &&
- !Found->hasExternalFormalLinkage();
-}
-
ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
SmallVector<Decl *, 2> Redecls = getCanonicalForwardRedeclChain(D);
@@ -3043,17 +3065,17 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
<< Name << D->getType() << FoundFunction->getType();
Importer.ToDiag(FoundFunction->getLocation(), diag::note_odr_value_here)
<< FoundFunction->getType();
+ ConflictingDecls.push_back(FoundDecl);
}
-
- ConflictingDecls.push_back(FoundDecl);
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, IDNS,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
@@ -3066,9 +3088,19 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (FoundByLookup) {
if (isa<CXXMethodDecl>(FoundByLookup)) {
if (D->getLexicalDeclContext() == D->getDeclContext()) {
- if (!D->doesThisDeclarationHaveABody())
+ if (!D->doesThisDeclarationHaveABody()) {
+ if (FunctionTemplateDecl *DescribedD =
+ D->getDescribedFunctionTemplate()) {
+ // Handle a "templated" function together with its described
+ // template. This avoids need for a similar check at import of the
+ // described template.
+ assert(FoundByLookup->getDescribedFunctionTemplate() &&
+ "Templated function mapped to non-templated?");
+ Importer.MapImported(DescribedD,
+ FoundByLookup->getDescribedFunctionTemplate());
+ }
return Importer.MapImported(D, FoundByLookup);
- else {
+ } else {
// Let's continue and build up the redecl chain in this case.
// FIXME Merge the functions into one decl.
}
@@ -3154,7 +3186,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (GetImportedOrCreateDecl<CXXDestructorDecl>(
ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(),
- D->isImplicit()))
+ D->isImplicit(), D->getConstexprKind()))
return ToFunction;
CXXDestructorDecl *ToDtor = cast<CXXDestructorDecl>(ToFunction);
@@ -3203,29 +3235,15 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// decl and its redeclarations may be required.
}
- // Import Ctor initializers.
- if (auto *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) {
- if (unsigned NumInitializers = FromConstructor->getNumCtorInitializers()) {
- SmallVector<CXXCtorInitializer *, 4> CtorInitializers(NumInitializers);
- // Import first, then allocate memory and copy if there was no error.
- if (Error Err = ImportContainerChecked(
- FromConstructor->inits(), CtorInitializers))
- return std::move(Err);
- auto **Memory =
- new (Importer.getToContext()) CXXCtorInitializer *[NumInitializers];
- std::copy(CtorInitializers.begin(), CtorInitializers.end(), Memory);
- auto *ToCtor = cast<CXXConstructorDecl>(ToFunction);
- ToCtor->setCtorInitializers(Memory);
- ToCtor->setNumCtorInitializers(NumInitializers);
- }
- }
-
ToFunction->setQualifierInfo(ToQualifierLoc);
ToFunction->setAccess(D->getAccess());
ToFunction->setLexicalDeclContext(LexicalDC);
ToFunction->setVirtualAsWritten(D->isVirtualAsWritten());
ToFunction->setTrivial(D->isTrivial());
ToFunction->setPure(D->isPure());
+ ToFunction->setDefaulted(D->isDefaulted());
+ ToFunction->setExplicitlyDefaulted(D->isExplicitlyDefaulted());
+ ToFunction->setDeletedAsWritten(D->isDeletedAsWritten());
ToFunction->setRangeEnd(ToEndLoc);
// Set the parameters.
@@ -3260,6 +3278,23 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
return ToFTOrErr.takeError();
}
+ // Import Ctor initializers.
+ if (auto *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) {
+ if (unsigned NumInitializers = FromConstructor->getNumCtorInitializers()) {
+ SmallVector<CXXCtorInitializer *, 4> CtorInitializers(NumInitializers);
+ // Import first, then allocate memory and copy if there was no error.
+ if (Error Err = ImportContainerChecked(
+ FromConstructor->inits(), CtorInitializers))
+ return std::move(Err);
+ auto **Memory =
+ new (Importer.getToContext()) CXXCtorInitializer *[NumInitializers];
+ std::copy(CtorInitializers.begin(), CtorInitializers.end(), Memory);
+ auto *ToCtor = cast<CXXConstructorDecl>(ToFunction);
+ ToCtor->setCtorInitializers(Memory);
+ ToCtor->setNumCtorInitializers(NumInitializers);
+ }
+ }
+
if (D->doesThisDeclarationHaveABody()) {
Error Err = ImportFunctionDeclBody(D, ToFunction);
@@ -3292,7 +3327,9 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D))
- ImportOverrides(cast<CXXMethodDecl>(ToFunction), FromCXXMethod);
+ if (Error Err = ImportOverriddenMethods(cast<CXXMethodDecl>(ToFunction),
+ FromCXXMethod))
+ return std::move(Err);
// Import the rest of the chain. I.e. import all subsequent declarations.
for (++RedeclIt; RedeclIt != Redecls.end(); ++RedeclIt) {
@@ -3686,17 +3723,17 @@ ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) {
<< Name << D->getType() << FoundVar->getType();
Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here)
<< FoundVar->getType();
+ ConflictingDecls.push_back(FoundDecl);
}
-
- ConflictingDecls.push_back(FoundDecl);
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, IDNS,
- ConflictingDecls.data(),
- ConflictingDecls.size());
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
}
@@ -3772,6 +3809,28 @@ ExpectedDecl ASTNodeImporter::VisitImplicitParamDecl(ImplicitParamDecl *D) {
return ToParm;
}
+Error ASTNodeImporter::ImportDefaultArgOfParmVarDecl(
+ const ParmVarDecl *FromParam, ParmVarDecl *ToParam) {
+ ToParam->setHasInheritedDefaultArg(FromParam->hasInheritedDefaultArg());
+ ToParam->setKNRPromoted(FromParam->isKNRPromoted());
+
+ if (FromParam->hasUninstantiatedDefaultArg()) {
+ if (auto ToDefArgOrErr = import(FromParam->getUninstantiatedDefaultArg()))
+ ToParam->setUninstantiatedDefaultArg(*ToDefArgOrErr);
+ else
+ return ToDefArgOrErr.takeError();
+ } else if (FromParam->hasUnparsedDefaultArg()) {
+ ToParam->setUnparsedDefaultArg();
+ } else if (FromParam->hasDefaultArg()) {
+ if (auto ToDefArgOrErr = import(FromParam->getDefaultArg()))
+ ToParam->setDefaultArg(*ToDefArgOrErr);
+ else
+ return ToDefArgOrErr.takeError();
+ }
+
+ return Error::success();
+}
+
ExpectedDecl ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
// Parameters are created in the translation unit's context, then moved
// into the function declaration's context afterward.
@@ -3798,23 +3857,11 @@ ExpectedDecl ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
/*DefaultArg*/ nullptr))
return ToParm;
- // Set the default argument.
- ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg());
- ToParm->setKNRPromoted(D->isKNRPromoted());
-
- if (D->hasUninstantiatedDefaultArg()) {
- if (auto ToDefArgOrErr = import(D->getUninstantiatedDefaultArg()))
- ToParm->setUninstantiatedDefaultArg(*ToDefArgOrErr);
- else
- return ToDefArgOrErr.takeError();
- } else if (D->hasUnparsedDefaultArg()) {
- ToParm->setUnparsedDefaultArg();
- } else if (D->hasDefaultArg()) {
- if (auto ToDefArgOrErr = import(D->getDefaultArg()))
- ToParm->setDefaultArg(*ToDefArgOrErr);
- else
- return ToDefArgOrErr.takeError();
- }
+ // Set the default argument. It should be no problem if it was already done.
+ // Do not import the default expression before GetImportedOrCreateDecl call
+ // to avoid possible infinite import loop because circular dependency.
+ if (Error Err = ImportDefaultArgOfParmVarDecl(D, ToParm))
+ return std::move(Err);
if (D->isObjCMethodParameter()) {
ToParm->setObjCMethodScopeInfo(D->getFunctionScopeIndex());
@@ -5016,25 +5063,27 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (IsStructuralMatch(D, FoundTemplate)) {
ClassTemplateDecl *TemplateWithDef =
getTemplateDefinition(FoundTemplate);
- if (D->isThisDeclarationADefinition() && TemplateWithDef) {
+ if (D->isThisDeclarationADefinition() && TemplateWithDef)
return Importer.MapImported(D, TemplateWithDef);
- }
- FoundByLookup = FoundTemplate;
- break;
+ if (!FoundByLookup)
+ FoundByLookup = FoundTemplate;
+ // Search in all matches because there may be multiple decl chains,
+ // see ASTTests test ImportExistingFriendClassTemplateDef.
+ continue;
}
+ ConflictingDecls.push_back(FoundDecl);
}
-
- ConflictingDecls.push_back(FoundDecl);
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary,
- ConflictingDecls.data(),
- ConflictingDecls.size());
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, Decl::IDNS_Ordinary, ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
-
- if (!Name)
- return make_error<ImportError>(ImportError::NameConflict);
}
CXXRecordDecl *FromTemplated = D->getTemplatedDecl();
@@ -5307,22 +5356,20 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
FoundTemplate->getTemplatedDecl());
return Importer.MapImported(D, FoundTemplate);
}
+ ConflictingDecls.push_back(FoundDecl);
}
-
- ConflictingDecls.push_back(FoundDecl);
}
if (!ConflictingDecls.empty()) {
- Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary,
- ConflictingDecls.data(),
- ConflictingDecls.size());
+ ExpectedName NameOrErr = Importer.HandleNameConflict(
+ Name, DC, Decl::IDNS_Ordinary, ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (NameOrErr)
+ Name = NameOrErr.get();
+ else
+ return NameOrErr.takeError();
}
- if (!Name)
- // FIXME: Is it possible to get other error than name conflict?
- // (Put this `if` into the previous `if`?)
- return make_error<ImportError>(ImportError::NameConflict);
-
VarDecl *DTemplated = D->getTemplatedDecl();
// Import the type.
@@ -5533,17 +5580,16 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
continue;
if (auto *FoundTemplate = dyn_cast<FunctionTemplateDecl>(FoundDecl)) {
- if (FoundTemplate->hasExternalFormalLinkage() &&
- D->hasExternalFormalLinkage()) {
- if (IsStructuralMatch(D, FoundTemplate)) {
- FunctionTemplateDecl *TemplateWithDef =
- getTemplateDefinition(FoundTemplate);
- if (D->isThisDeclarationADefinition() && TemplateWithDef) {
- return Importer.MapImported(D, TemplateWithDef);
- }
- FoundByLookup = FoundTemplate;
- break;
- }
+ if (!hasSameVisibilityContext(FoundTemplate, D))
+ continue;
+ if (IsStructuralMatch(D, FoundTemplate)) {
+ FunctionTemplateDecl *TemplateWithDef =
+ getTemplateDefinition(FoundTemplate);
+ if (D->isThisDeclarationADefinition() && TemplateWithDef)
+ return Importer.MapImported(D, TemplateWithDef);
+
+ FoundByLookup = FoundTemplate;
+ break;
// TODO: handle conflicting names
}
}
@@ -6868,8 +6914,23 @@ ExpectedStmt ASTNodeImporter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
if (!UsedContextOrErr)
return UsedContextOrErr.takeError();
- return CXXDefaultArgExpr::Create(
- Importer.getToContext(), *ToUsedLocOrErr, *ToParamOrErr, *UsedContextOrErr);
+ // Import the default arg if it was not imported yet.
+ // This is needed because it can happen that during the import of the
+ // default expression (from VisitParmVarDecl) the same ParmVarDecl is
+ // encountered here. The default argument for a ParmVarDecl is set in the
+ // ParmVarDecl only after it is imported (set in VisitParmVarDecl if not here,
+ // see VisitParmVarDecl).
+ ParmVarDecl *ToParam = *ToParamOrErr;
+ if (!ToParam->getDefaultArg()) {
+ Optional<ParmVarDecl *> FromParam = Importer.getImportedFromDecl(ToParam);
+ assert(FromParam && "ParmVarDecl was not imported?");
+
+ if (Error Err = ImportDefaultArgOfParmVarDecl(*FromParam, ToParam))
+ return std::move(Err);
+ }
+
+ return CXXDefaultArgExpr::Create(Importer.getToContext(), *ToUsedLocOrErr,
+ *ToParamOrErr, *UsedContextOrErr);
}
ExpectedStmt
@@ -7701,15 +7762,18 @@ ExpectedStmt ASTNodeImporter::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
*ToTypeOrErr, *ToExprOperandOrErr, *ToSourceRangeOrErr);
}
-void ASTNodeImporter::ImportOverrides(CXXMethodDecl *ToMethod,
- CXXMethodDecl *FromMethod) {
+Error ASTNodeImporter::ImportOverriddenMethods(CXXMethodDecl *ToMethod,
+ CXXMethodDecl *FromMethod) {
+ Error ImportErrors = Error::success();
for (auto *FromOverriddenMethod : FromMethod->overridden_methods()) {
if (auto ImportedOrErr = import(FromOverriddenMethod))
ToMethod->getCanonicalDecl()->addOverriddenMethod(cast<CXXMethodDecl>(
(*ImportedOrErr)->getCanonicalDecl()));
else
- consumeError(ImportedOrErr.takeError());
+ ImportErrors =
+ joinErrors(std::move(ImportErrors), ImportedOrErr.takeError());
}
+ return ImportErrors;
}
ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
@@ -7718,7 +7782,7 @@ ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
std::shared_ptr<ASTImporterSharedState> SharedState)
: SharedState(SharedState), ToContext(ToContext), FromContext(FromContext),
ToFileManager(ToFileManager), FromFileManager(FromFileManager),
- Minimal(MinimalImport) {
+ Minimal(MinimalImport), ODRHandling(ODRHandlingType::Conservative) {
// Create a default state without the lookup table: LLDB case.
if (!SharedState) {
@@ -8390,13 +8454,13 @@ Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) {
// disk again
// FIXME: We definitely want to re-use the existing MemoryBuffer, rather
// than mmap the files several times.
- const FileEntry *Entry =
+ auto Entry =
ToFileManager.getFile(Cache->OrigEntry->getName());
// FIXME: The filename may be a virtual name that does probably not
// point to a valid file and we get no Entry here. In this case try with
// the memory buffer below.
if (Entry)
- ToID = ToSM.createFileID(Entry, *ToIncludeLoc,
+ ToID = ToSM.createFileID(*Entry, *ToIncludeLoc,
FromSLoc.getFile().getFileCharacteristic());
}
}
@@ -8404,8 +8468,9 @@ Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) {
if (ToID.isInvalid() || IsBuiltin) {
// FIXME: We want to re-use the existing MemoryBuffer!
bool Invalid = true;
- const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(
- FromContext.getDiagnostics(), FromSM, SourceLocation{}, &Invalid);
+ const llvm::MemoryBuffer *FromBuf =
+ Cache->getBuffer(FromContext.getDiagnostics(),
+ FromSM.getFileManager(), SourceLocation{}, &Invalid);
if (!FromBuf || Invalid)
// FIXME: Use a new error kind?
return llvm::make_error<ImportError>(ImportError::Unknown);
@@ -8421,6 +8486,10 @@ Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) {
assert(ToID.isValid() && "Unexpected invalid fileID was created.");
ImportedFileIDs[FromID] = ToID;
+
+ if (FileIDImportHandler)
+ FileIDImportHandler(ToID, FromID);
+
return ToID;
}
@@ -8640,12 +8709,17 @@ Expected<Selector> ASTImporter::Import(Selector FromSel) {
return ToContext.Selectors.getSelector(FromSel.getNumArgs(), Idents.data());
}
-DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name,
- DeclContext *DC,
- unsigned IDNS,
- NamedDecl **Decls,
- unsigned NumDecls) {
- return Name;
+Expected<DeclarationName> ASTImporter::HandleNameConflict(DeclarationName Name,
+ DeclContext *DC,
+ unsigned IDNS,
+ NamedDecl **Decls,
+ unsigned NumDecls) {
+ if (ODRHandling == ODRHandlingType::Conservative)
+ // Report error at any name conflict.
+ return make_error<ImportError>(ImportError::NameConflict);
+ else
+ // Allow to create the new Decl with the same name.
+ return Name;
}
DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) {
diff --git a/lib/AST/ASTStructuralEquivalence.cpp b/lib/AST/ASTStructuralEquivalence.cpp
index 912db3c130c5..db48405055cd 100644
--- a/lib/AST/ASTStructuralEquivalence.cpp
+++ b/lib/AST/ASTStructuralEquivalence.cpp
@@ -235,12 +235,21 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const TemplateName &N1,
const TemplateName &N2) {
- if (N1.getKind() != N2.getKind())
+ TemplateDecl *TemplateDeclN1 = N1.getAsTemplateDecl();
+ TemplateDecl *TemplateDeclN2 = N2.getAsTemplateDecl();
+ if (TemplateDeclN1 && TemplateDeclN2) {
+ if (!IsStructurallyEquivalent(Context, TemplateDeclN1, TemplateDeclN2))
+ return false;
+ // If the kind is different we compare only the template decl.
+ if (N1.getKind() != N2.getKind())
+ return true;
+ } else if (TemplateDeclN1 || TemplateDeclN2)
+ return false;
+ else if (N1.getKind() != N2.getKind())
return false;
+
+ // Check for special case incompatibilities.
switch (N1.getKind()) {
- case TemplateName::Template:
- return IsStructurallyEquivalent(Context, N1.getAsTemplateDecl(),
- N2.getAsTemplateDecl());
case TemplateName::OverloadedTemplate: {
OverloadedTemplateStorage *OS1 = N1.getAsOverloadedTemplate(),
@@ -259,14 +268,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return TN1->getDeclName() == TN2->getDeclName();
}
- case TemplateName::QualifiedTemplate: {
- QualifiedTemplateName *QN1 = N1.getAsQualifiedTemplateName(),
- *QN2 = N2.getAsQualifiedTemplateName();
- return IsStructurallyEquivalent(Context, QN1->getDecl(), QN2->getDecl()) &&
- IsStructurallyEquivalent(Context, QN1->getQualifier(),
- QN2->getQualifier());
- }
-
case TemplateName::DependentTemplate: {
DependentTemplateName *DN1 = N1.getAsDependentTemplateName(),
*DN2 = N2.getAsDependentTemplateName();
@@ -281,15 +282,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
}
- case TemplateName::SubstTemplateTemplateParm: {
- SubstTemplateTemplateParmStorage *TS1 = N1.getAsSubstTemplateTemplateParm(),
- *TS2 = N2.getAsSubstTemplateTemplateParm();
- return IsStructurallyEquivalent(Context, TS1->getParameter(),
- TS2->getParameter()) &&
- IsStructurallyEquivalent(Context, TS1->getReplacement(),
- TS2->getReplacement());
- }
-
case TemplateName::SubstTemplateTemplateParmPack: {
SubstTemplateTemplateParmPackStorage
*P1 = N1.getAsSubstTemplateTemplateParmPack(),
@@ -299,8 +291,16 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
IsStructurallyEquivalent(Context, P1->getParameterPack(),
P2->getParameterPack());
}
+
+ case TemplateName::Template:
+ case TemplateName::QualifiedTemplate:
+ case TemplateName::SubstTemplateTemplateParm:
+ // It is sufficient to check value of getAsTemplateDecl.
+ break;
+
}
- return false;
+
+ return true;
}
/// Determine whether two template arguments are equivalent.
@@ -1574,20 +1574,24 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Decl *D1, Decl *D2) {
// FIXME: Check for known structural equivalences via a callback of some sort.
+ D1 = D1->getCanonicalDecl();
+ D2 = D2->getCanonicalDecl();
+ std::pair<Decl *, Decl *> P{D1, D2};
+
// Check whether we already know that these two declarations are not
// structurally equivalent.
- if (Context.NonEquivalentDecls.count(
- std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl())))
+ if (Context.NonEquivalentDecls.count(P))
return false;
- // Determine whether we've already produced a tentative equivalence for D1.
- Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()];
- if (EquivToD1)
- return EquivToD1 == D2->getCanonicalDecl();
+ // Check if a check for these declarations is already pending.
+ // If yes D1 and D2 will be checked later (from DeclsToCheck),
+ // or these are already checked (and equivalent).
+ bool Inserted = Context.VisitedDecls.insert(P).second;
+ if (!Inserted)
+ return true;
+
+ Context.DeclsToCheck.push(P);
- // Produce a tentative equivalence D1 <-> D2, which will be checked later.
- EquivToD1 = D2->getCanonicalDecl();
- Context.DeclsToCheck.push_back(D1->getCanonicalDecl());
return true;
}
@@ -1703,11 +1707,13 @@ bool StructuralEquivalenceContext::IsEquivalent(Decl *D1, Decl *D2) {
// Ensure that the implementation functions (all static functions in this TU)
// never call the public ASTStructuralEquivalence::IsEquivalent() functions,
// because that will wreak havoc the internal state (DeclsToCheck and
- // TentativeEquivalences members) and can cause faulty behaviour. For
- // instance, some leaf declarations can be stated and cached as inequivalent
- // as a side effect of one inequivalent element in the DeclsToCheck list.
+ // VisitedDecls members) and can cause faulty behaviour.
+ // In other words: Do not start a graph search from a new node with the
+ // internal data of another search in progress.
+ // FIXME: Better encapsulation and separation of internal and public
+ // functionality.
assert(DeclsToCheck.empty());
- assert(TentativeEquivalences.empty());
+ assert(VisitedDecls.empty());
if (!::IsStructurallyEquivalent(*this, D1, D2))
return false;
@@ -1717,7 +1723,7 @@ bool StructuralEquivalenceContext::IsEquivalent(Decl *D1, Decl *D2) {
bool StructuralEquivalenceContext::IsEquivalent(QualType T1, QualType T2) {
assert(DeclsToCheck.empty());
- assert(TentativeEquivalences.empty());
+ assert(VisitedDecls.empty());
if (!::IsStructurallyEquivalent(*this, T1, T2))
return false;
@@ -1876,11 +1882,11 @@ bool StructuralEquivalenceContext::CheckKindSpecificEquivalence(
bool StructuralEquivalenceContext::Finish() {
while (!DeclsToCheck.empty()) {
// Check the next declaration.
- Decl *D1 = DeclsToCheck.front();
- DeclsToCheck.pop_front();
+ std::pair<Decl *, Decl *> P = DeclsToCheck.front();
+ DeclsToCheck.pop();
- Decl *D2 = TentativeEquivalences[D1];
- assert(D2 && "Unrecorded tentative equivalence?");
+ Decl *D1 = P.first;
+ Decl *D2 = P.second;
bool Equivalent =
CheckCommonEquivalence(D1, D2) && CheckKindSpecificEquivalence(D1, D2);
@@ -1888,8 +1894,8 @@ bool StructuralEquivalenceContext::Finish() {
if (!Equivalent) {
// Note that these two declarations are not equivalent (and we already
// know about it).
- NonEquivalentDecls.insert(
- std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl()));
+ NonEquivalentDecls.insert(P);
+
return true;
}
}
diff --git a/lib/AST/ASTTypeTraits.cpp b/lib/AST/ASTTypeTraits.cpp
index ba1581bd3f6b..6b7f6ec51086 100644
--- a/lib/AST/ASTTypeTraits.cpp
+++ b/lib/AST/ASTTypeTraits.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/NestedNameSpecifier.h"
namespace clang {
namespace ast_type_traits {
@@ -36,7 +37,7 @@ const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = {
#include "clang/AST/StmtNodes.inc"
{ NKI_None, "Type" },
#define TYPE(DERIVED, BASE) { NKI_##BASE, #DERIVED "Type" },
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
{ NKI_None, "OMPClause" },
#define OPENMP_CLAUSE(TextualSpelling, Class) {NKI_OMPClause, #Class},
#include "clang/Basic/OpenMPKinds.def"
@@ -103,7 +104,7 @@ ASTNodeKind ASTNodeKind::getFromNode(const Type &T) {
#define TYPE(Class, Base) \
case Type::Class: return ASTNodeKind(NKI_##Class##Type);
#define ABSTRACT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
llvm_unreachable("invalid type kind");
}
@@ -115,6 +116,8 @@ ASTNodeKind ASTNodeKind::getFromNode(const OMPClause &C) {
#include "clang/Basic/OpenMPKinds.def"
case OMPC_threadprivate:
case OMPC_uniform:
+ case OMPC_device_type:
+ case OMPC_match:
case OMPC_unknown:
llvm_unreachable("unexpected OpenMP clause kind");
}
@@ -129,9 +132,12 @@ void DynTypedNode::print(llvm::raw_ostream &OS,
TN->print(OS, PP);
else if (const NestedNameSpecifier *NNS = get<NestedNameSpecifier>())
NNS->print(OS, PP);
- else if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>())
- NNSL->getNestedNameSpecifier()->print(OS, PP);
- else if (const QualType *QT = get<QualType>())
+ else if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>()) {
+ if (const NestedNameSpecifier *NNS = NNSL->getNestedNameSpecifier())
+ NNS->print(OS, PP);
+ else
+ OS << "(empty NestedNameSpecifierLoc)";
+ } else if (const QualType *QT = get<QualType>())
QT->print(OS, PP);
else if (const TypeLoc *TL = get<TypeLoc>())
TL->getType().print(OS, PP);
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index ecf451b175af..a3a3794b2edd 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -44,7 +44,7 @@ void CXXBasePaths::ComputeDeclsFound() {
Decls.insert(Path->Decls.front());
NumDeclsFound = Decls.size();
- DeclsFound = llvm::make_unique<NamedDecl *[]>(NumDeclsFound);
+ DeclsFound = std::make_unique<NamedDecl *[]>(NumDeclsFound);
std::copy(Decls.begin(), Decls.end(), DeclsFound.get());
}
diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp
index 25339c7901e3..23dc7ba93591 100644
--- a/lib/AST/Comment.cpp
+++ b/lib/AST/Comment.cpp
@@ -13,10 +13,25 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/CharInfo.h"
#include "llvm/Support/ErrorHandling.h"
+#include <type_traits>
namespace clang {
namespace comments {
+// Check that no comment class has a non-trival destructor. They are allocated
+// with a BumpPtrAllocator and therefore their destructor is not executed.
+#define ABSTRACT_COMMENT(COMMENT)
+#define COMMENT(CLASS, PARENT) \
+ static_assert(std::is_trivially_destructible<CLASS>::value, \
+ #CLASS " should be trivially destructible!");
+#include "clang/AST/CommentNodes.inc"
+#undef COMMENT
+#undef ABSTRACT_COMMENT
+
+// DeclInfo is also allocated with a BumpPtrAllocator.
+static_assert(std::is_trivially_destructible<DeclInfo>::value,
+ "DeclInfo should be trivially destructible!");
+
const char *Comment::getCommentKindName() const {
switch (getCommentKind()) {
case NoCommentKind: return "NoCommentKind";
diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp
index 19485f6018c0..c1ea3eab075e 100644
--- a/lib/AST/CommentLexer.cpp
+++ b/lib/AST/CommentLexer.cpp
@@ -850,17 +850,14 @@ again:
}
StringRef Lexer::getSpelling(const Token &Tok,
- const SourceManager &SourceMgr,
- bool *Invalid) const {
+ const SourceManager &SourceMgr) const {
SourceLocation Loc = Tok.getLocation();
std::pair<FileID, unsigned> LocInfo = SourceMgr.getDecomposedLoc(Loc);
bool InvalidTemp = false;
StringRef File = SourceMgr.getBufferData(LocInfo.first, &InvalidTemp);
- if (InvalidTemp) {
- *Invalid = true;
+ if (InvalidTemp)
return StringRef();
- }
const char *Begin = File.data() + LocInfo.second;
return StringRef(Begin, Tok.getLength());
diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp
index c7f8aa7e16a0..29983b0a16c3 100644
--- a/lib/AST/CommentParser.cpp
+++ b/lib/AST/CommentParser.cpp
@@ -422,6 +422,12 @@ InlineCommandComment *Parser::parseInlineCommand() {
IC = S.actOnInlineCommand(CommandTok.getLocation(),
CommandTok.getEndLocation(),
CommandTok.getCommandID());
+
+ Diag(CommandTok.getEndLocation().getLocWithOffset(1),
+ diag::warn_doc_inline_contents_no_argument)
+ << CommandTok.is(tok::at_command)
+ << Traits.getCommandInfo(CommandTok.getCommandID())->Name
+ << SourceRange(CommandTok.getLocation(), CommandTok.getEndLocation());
}
Retokenizer.putBackLeftoverTokens();
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index 067b3ae4222e..69d61dc55162 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -588,6 +588,8 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
if (isObjCPropertyDecl())
return;
if (isFunctionDecl() || isFunctionOrBlockPointerVarLikeDecl()) {
+ assert(!ThisDeclInfo->ReturnType.isNull() &&
+ "should have a valid return type");
if (ThisDeclInfo->ReturnType->isVoidType()) {
unsigned DiagKind;
switch (ThisDeclInfo->CommentDecl->getKind()) {
@@ -873,6 +875,12 @@ bool Sema::isFunctionOrBlockPointerVarLikeDecl() {
// can be ignored.
if (QT->getAs<TypedefType>())
return false;
+ if (const auto *P = QT->getAs<PointerType>())
+ if (P->getPointeeType()->getAs<TypedefType>())
+ return false;
+ if (const auto *P = QT->getAs<BlockPointerType>())
+ if (P->getPointeeType()->getAs<TypedefType>())
+ return false;
return QT->isFunctionPointerType() || QT->isBlockPointerType();
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 21cf9da18a8b..80235d8496d2 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1385,7 +1385,8 @@ LinkageInfo LinkageComputer::computeLVForDecl(const NamedDecl *D,
case Decl::CXXRecord: {
const auto *Record = cast<CXXRecordDecl>(D);
if (Record->isLambda()) {
- if (!Record->getLambdaManglingNumber()) {
+ if (Record->hasKnownLambdaInternalLinkage() ||
+ !Record->getLambdaManglingNumber()) {
// This lambda has no mangling number, so it's internal.
return getInternalLinkageFor(D);
}
@@ -1402,7 +1403,8 @@ LinkageInfo LinkageComputer::computeLVForDecl(const NamedDecl *D,
// };
const CXXRecordDecl *OuterMostLambda =
getOutermostEnclosingLambda(Record);
- if (!OuterMostLambda->getLambdaManglingNumber())
+ if (OuterMostLambda->hasKnownLambdaInternalLinkage() ||
+ !OuterMostLambda->getLambdaManglingNumber())
return getInternalLinkageFor(D);
return getLVForClosure(
@@ -1558,6 +1560,24 @@ void NamedDecl::printQualifiedName(raw_ostream &OS) const {
void NamedDecl::printQualifiedName(raw_ostream &OS,
const PrintingPolicy &P) const {
+ if (getDeclContext()->isFunctionOrMethod()) {
+ // We do not print '(anonymous)' for function parameters without name.
+ printName(OS);
+ return;
+ }
+ printNestedNameSpecifier(OS, P);
+ if (getDeclName() || isa<DecompositionDecl>(this))
+ OS << *this;
+ else
+ OS << "(anonymous)";
+}
+
+void NamedDecl::printNestedNameSpecifier(raw_ostream &OS) const {
+ printNestedNameSpecifier(OS, getASTContext().getPrintingPolicy());
+}
+
+void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
+ const PrintingPolicy &P) const {
const DeclContext *Ctx = getDeclContext();
// For ObjC methods and properties, look through categories and use the
@@ -1571,10 +1591,8 @@ void NamedDecl::printQualifiedName(raw_ostream &OS,
Ctx = ID;
}
- if (Ctx->isFunctionOrMethod()) {
- printName(OS);
+ if (Ctx->isFunctionOrMethod())
return;
- }
using ContextsTy = SmallVector<const DeclContext *, 8>;
ContextsTy Contexts;
@@ -1644,11 +1662,6 @@ void NamedDecl::printQualifiedName(raw_ostream &OS,
}
OS << "::";
}
-
- if (getDeclName() || isa<DecompositionDecl>(this))
- OS << *this;
- else
- OS << "(anonymous)";
}
void NamedDecl::getNameForDiagnostic(raw_ostream &OS,
@@ -2220,6 +2233,22 @@ Stmt **VarDecl::getInitAddress() {
return Init.getAddrOfPtr1();
}
+VarDecl *VarDecl::getInitializingDeclaration() {
+ VarDecl *Def = nullptr;
+ for (auto I : redecls()) {
+ if (I->hasInit())
+ return I;
+
+ if (I->isThisDeclarationADefinition()) {
+ if (isStaticDataMember())
+ return I;
+ else
+ Def = I;
+ }
+ }
+ return Def;
+}
+
bool VarDecl::isOutOfLine() const {
if (Decl::isOutOfLine())
return true;
@@ -2565,6 +2594,18 @@ bool VarDecl::isNoDestroy(const ASTContext &Ctx) const {
!hasAttr<AlwaysDestroyAttr>()));
}
+QualType::DestructionKind
+VarDecl::needsDestruction(const ASTContext &Ctx) const {
+ if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>())
+ if (Eval->HasConstantDestruction)
+ return QualType::DK_none;
+
+ if (isNoDestroy(Ctx))
+ return QualType::DK_none;
+
+ return getType().isDestructedType();
+}
+
MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const {
if (isStaticDataMember())
// FIXME: Remove ?
@@ -2950,8 +2991,7 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction(bool *IsAligned) const
Ty = Ty->getPointeeType();
if (Ty.getCVRQualifiers() != Qualifiers::Const)
return false;
- const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
- if (RD && isNamed(RD, "nothrow_t") && RD->isInStdNamespace())
+ if (Ty->isNothrowT())
Consume();
}
@@ -3235,6 +3275,9 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
return true;
}
+ if (Context.getLangOpts().CPlusPlus)
+ return false;
+
if (Context.getLangOpts().GNUInline || hasAttr<GNUInlineAttr>()) {
// With GNU inlining, a declaration with 'inline' but not 'extern', forces
// an externally visible definition.
@@ -3263,9 +3306,6 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
return FoundBody;
}
- if (Context.getLangOpts().CPlusPlus)
- 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,
@@ -3332,7 +3372,8 @@ SourceRange FunctionDecl::getExceptionSpecSourceRange() const {
/// an externally visible symbol, but "extern inline" will not create an
/// externally visible symbol.
bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
- assert((doesThisDeclarationHaveABody() || willHaveBody()) &&
+ assert((doesThisDeclarationHaveABody() || willHaveBody() ||
+ hasAttr<AliasAttr>()) &&
"Must be a function definition");
assert(isInlined() && "Function must be inline");
ASTContext &Context = getASTContext();
@@ -3344,6 +3385,8 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
// If it's not the case that both 'inline' and 'extern' are
// specified on the definition, then this inline definition is
// externally visible.
+ if (Context.getLangOpts().CPlusPlus)
+ return false;
if (!(isInlineSpecified() && getStorageClass() == SC_Extern))
return true;
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index fd80e1532eb5..77a3a4c679a1 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/DeclBase.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/Attr.h"
#include "clang/AST/AttrIterator.h"
@@ -99,7 +100,7 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Ctx,
// Ensure required alignment of the resulting object by adding extra
// padding at the start if required.
size_t ExtraAlign =
- llvm::OffsetToAlignment(sizeof(Module *), alignof(Decl));
+ llvm::offsetToAlignment(sizeof(Module *), llvm::Align(alignof(Decl)));
auto *Buffer = reinterpret_cast<char *>(
::operator new(ExtraAlign + sizeof(Module *) + Size + Extra, Ctx));
Buffer += ExtraAlign;
@@ -958,11 +959,11 @@ const FunctionType *Decl::getFunctionType(bool BlocksToo) const {
return nullptr;
if (Ty->isFunctionPointerType())
- Ty = Ty->getAs<PointerType>()->getPointeeType();
+ Ty = Ty->castAs<PointerType>()->getPointeeType();
else if (Ty->isFunctionReferenceType())
- Ty = Ty->getAs<ReferenceType>()->getPointeeType();
+ Ty = Ty->castAs<ReferenceType>()->getPointeeType();
else if (BlocksToo && Ty->isBlockPointerType())
- Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
+ Ty = Ty->castAs<BlockPointerType>()->getPointeeType();
return Ty->getAs<FunctionType>();
}
@@ -1043,6 +1044,12 @@ DeclContext *DeclContext::getLookupParent() {
getLexicalParent()->getRedeclContext()->isRecord())
return getLexicalParent();
+ // A lookup within the call operator of a lambda never looks in the lambda
+ // class; instead, skip to the context in which that closure type is
+ // declared.
+ if (isLambdaCallOperator(this))
+ return getParent()->getParent();
+
return getParent();
}
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 59710a55498f..12ec44fa0279 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -95,14 +95,16 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
HasDefaultedDefaultConstructor(false),
DefaultedDefaultConstructorIsConstexpr(true),
HasConstexprDefaultConstructor(false),
- HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
+ DefaultedDestructorIsConstexpr(true),
+ HasNonLiteralTypeFieldsOrBases(false),
UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0),
ImplicitCopyConstructorCanHaveConstParamForVBase(true),
ImplicitCopyConstructorCanHaveConstParamForNonVBase(true),
ImplicitCopyAssignmentHasConstParam(true),
HasDeclaredCopyConstructorWithConstParam(false),
HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false),
- IsParsingBaseSpecifiers(false), HasODRHash(false), Definition(D) {}
+ IsParsingBaseSpecifiers(false), ComputedVisibleConversions(false),
+ HasODRHash(false), Definition(D) {}
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
return Bases.get(Definition->getASTContext().getExternalSource());
@@ -217,7 +219,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
if (BaseType->isDependentType())
continue;
auto *BaseClassDecl =
- cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(BaseType->castAs<RecordType>()->getDecl());
// C++2a [class]p7:
// A standard-layout class is a class that:
@@ -325,10 +327,12 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().IsStandardLayout = false;
data().IsCXX11StandardLayout = false;
- // C++11 [dcl.constexpr]p4:
- // In the definition of a constexpr constructor [...]
- // -- the class shall not have any virtual base classes
+ // C++20 [dcl.constexpr]p3:
+ // In the definition of a constexpr function [...]
+ // -- if the function is a constructor or destructor,
+ // its class shall not have any virtual base classes
data().DefaultedDefaultConstructorIsConstexpr = false;
+ data().DefaultedDestructorIsConstexpr = false;
// C++1z [class.copy]p8:
// The implicitly-declared copy constructor for a class X will have
@@ -520,6 +524,19 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
data().NeedOverloadResolutionForMoveConstructor = true;
data().NeedOverloadResolutionForDestructor = true;
}
+
+ // C++2a [dcl.constexpr]p4:
+ // The definition of a constexpr destructor [shall] satisfy the
+ // following requirement:
+ // -- for every subobject of class type or (possibly multi-dimensional)
+ // array thereof, that class type shall have a constexpr destructor
+ if (!Subobj->hasConstexprDestructor())
+ data().DefaultedDestructorIsConstexpr = false;
+}
+
+bool CXXRecordDecl::hasConstexprDestructor() const {
+ auto *Dtor = getDestructor();
+ return Dtor ? Dtor->isConstexpr() : defaultedDestructorIsConstexpr();
}
bool CXXRecordDecl::hasAnyDependentBases() const {
@@ -1263,7 +1280,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
} else {
// Base element type of field is a non-class type.
if (!T->isLiteralType(Context) ||
- (!Field->hasInClassInitializer() && !isUnion()))
+ (!Field->hasInClassInitializer() && !isUnion() &&
+ !Context.getLangOpts().CPlusPlus2a))
data().DefaultedDefaultConstructorIsConstexpr = false;
// C++11 [class.copy]p23:
@@ -1382,17 +1400,29 @@ static bool allLookupResultsAreTheSame(const DeclContext::lookup_result &R) {
}
#endif
-CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const {
- if (!isLambda()) return nullptr;
+static NamedDecl* getLambdaCallOperatorHelper(const CXXRecordDecl &RD) {
+ if (!RD.isLambda()) return nullptr;
DeclarationName Name =
- getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
- DeclContext::lookup_result Calls = lookup(Name);
+ RD.getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
+ DeclContext::lookup_result Calls = RD.lookup(Name);
assert(!Calls.empty() && "Missing lambda call operator!");
assert(allLookupResultsAreTheSame(Calls) &&
"More than one lambda call operator!");
+ return Calls.front();
+}
+
+FunctionTemplateDecl* CXXRecordDecl::getDependentLambdaCallOperator() const {
+ NamedDecl *CallOp = getLambdaCallOperatorHelper(*this);
+ return dyn_cast_or_null<FunctionTemplateDecl>(CallOp);
+}
+
+CXXMethodDecl *CXXRecordDecl::getLambdaCallOperator() const {
+ NamedDecl *CallOp = getLambdaCallOperatorHelper(*this);
+
+ if (CallOp == nullptr)
+ return nullptr;
- NamedDecl *CallOp = Calls.front();
if (const auto *CallOpTmpl = dyn_cast<FunctionTemplateDecl>(CallOp))
return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl());
@@ -1880,7 +1910,7 @@ bool CXXRecordDecl::mayBeAbstract() const {
for (const auto &B : bases()) {
const auto *BaseDecl =
- cast<CXXRecordDecl>(B.getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(B.getType()->castAs<RecordType>()->getDecl());
if (BaseDecl->isAbstract())
return true;
}
@@ -2067,10 +2097,15 @@ CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base,
if (DevirtualizedMethod->hasAttr<FinalAttr>())
return DevirtualizedMethod;
- // Similarly, if the class itself is marked 'final' it can't be overridden
- // and we can therefore devirtualize the member function call.
+ // Similarly, if the class itself or its destructor is marked 'final',
+ // the class can't be derived from and we can therefore devirtualize the
+ // member function call.
if (BestDynamicDecl->hasAttr<FinalAttr>())
return DevirtualizedMethod;
+ if (const auto *dtor = BestDynamicDecl->getDestructor()) {
+ if (dtor->hasAttr<FinalAttr>())
+ return DevirtualizedMethod;
+ }
if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
@@ -2532,7 +2567,7 @@ bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const {
return false;
return (getNumParams() == 0 &&
- getType()->getAs<FunctionProtoType>()->isVariadic()) ||
+ getType()->castAs<FunctionProtoType>()->isVariadic()) ||
(getNumParams() == 1) ||
(getNumParams() > 1 &&
(getParamDecl(1)->hasDefaultArg() ||
@@ -2565,20 +2600,19 @@ CXXDestructorDecl *
CXXDestructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID)
CXXDestructorDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(),
- QualType(), nullptr, false, false);
+ QualType(), nullptr, false, false, CSK_unspecified);
}
-CXXDestructorDecl *
-CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
- SourceLocation StartLoc,
- const DeclarationNameInfo &NameInfo,
- QualType T, TypeSourceInfo *TInfo,
- bool isInline, bool isImplicitlyDeclared) {
+CXXDestructorDecl *CXXDestructorDecl::Create(
+ ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
+ const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
+ bool isInline, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXDestructorName &&
"Name must refer to a destructor");
- return new (C, RD) CXXDestructorDecl(C, RD, StartLoc, NameInfo, T, TInfo,
- isInline, isImplicitlyDeclared);
+ return new (C, RD)
+ CXXDestructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline,
+ isImplicitlyDeclared, ConstexprKind);
}
void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD, Expr *ThisArg) {
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index f5c69944034a..608b0b44072b 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -1001,12 +1001,19 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
const char *l;
- if (D->getLanguage() == LinkageSpecDecl::lang_c)
+ switch (D->getLanguage()) {
+ case LinkageSpecDecl::lang_c:
l = "C";
- else {
- assert(D->getLanguage() == LinkageSpecDecl::lang_cxx &&
- "unknown language in linkage specification");
+ break;
+ case LinkageSpecDecl::lang_cxx_14:
+ l = "C++14";
+ break;
+ case LinkageSpecDecl::lang_cxx_11:
+ l = "C++11";
+ break;
+ case LinkageSpecDecl::lang_cxx:
l = "C++";
+ break;
}
Out << "extern \"" << l << "\" ";
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 40c39c845db6..7e013c6c54d8 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -70,6 +70,8 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
}
if (RequiresClause) {
*getTrailingObjects<Expr *>() = RequiresClause;
+ if (RequiresClause->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
}
}
@@ -136,6 +138,18 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,
}
}
+void TemplateParameterList::
+getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
+ // TODO: Concepts: Collect immediately-introduced constraints.
+ if (HasRequiresClause)
+ AC.push_back(getRequiresClause());
+}
+
+bool TemplateParameterList::hasAssociatedConstraints() const {
+ // TODO: Concepts: Regard immediately-introduced constraints.
+ return HasRequiresClause;
+}
+
namespace clang {
void *allocateDefaultArgStorageChain(const ASTContext &C) {
@@ -145,6 +159,28 @@ void *allocateDefaultArgStorageChain(const ASTContext &C) {
} // namespace clang
//===----------------------------------------------------------------------===//
+// TemplateDecl Implementation
+//===----------------------------------------------------------------------===//
+
+TemplateDecl::TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ DeclarationName Name, TemplateParameterList *Params,
+ NamedDecl *Decl)
+ : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl), TemplateParams(Params) {}
+
+void TemplateDecl::anchor() {}
+
+void TemplateDecl::
+getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
+ // TODO: Concepts: Append function trailing requires clause.
+ TemplateParams->getAssociatedConstraints(AC);
+}
+
+bool TemplateDecl::hasAssociatedConstraints() const {
+ // TODO: Concepts: Regard function trailing requires clause.
+ return TemplateParams->hasAssociatedConstraints();
+}
+
+//===----------------------------------------------------------------------===//
// RedeclarableTemplateDecl Implementation
//===----------------------------------------------------------------------===//
@@ -344,19 +380,10 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
- NamedDecl *Decl,
- Expr *AssociatedConstraints) {
+ NamedDecl *Decl) {
AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
- if (!AssociatedConstraints) {
- return new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl);
- }
-
- auto *const CTDI = new (C) ConstrainedTemplateDeclInfo;
- auto *const New =
- new (C, DC) ClassTemplateDecl(CTDI, C, DC, L, Name, Params, Decl);
- New->setAssociatedConstraints(AssociatedConstraints);
- return New;
+ return new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl);
}
ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
@@ -510,20 +537,24 @@ SourceRange TemplateTypeParmDecl::getSourceRange() const {
if (hasDefaultArgument() && !defaultArgumentWasInherited())
return SourceRange(getBeginLoc(),
getDefaultArgumentInfo()->getTypeLoc().getEndLoc());
- else
- return TypeDecl::getSourceRange();
+ // TypeDecl::getSourceRange returns a range containing name location, which is
+ // wrong for unnamed template parameters. e.g:
+ // it will return <[[typename>]] instead of <[[typename]]>
+ else if (getDeclName().isEmpty())
+ return SourceRange(getBeginLoc());
+ return TypeDecl::getSourceRange();
}
unsigned TemplateTypeParmDecl::getDepth() const {
- return getTypeForDecl()->getAs<TemplateTypeParmType>()->getDepth();
+ return getTypeForDecl()->castAs<TemplateTypeParmType>()->getDepth();
}
unsigned TemplateTypeParmDecl::getIndex() const {
- return getTypeForDecl()->getAs<TemplateTypeParmType>()->getIndex();
+ return getTypeForDecl()->castAs<TemplateTypeParmType>()->getIndex();
}
bool TemplateTypeParmDecl::isParameterPack() const {
- return getTypeForDecl()->getAs<TemplateTypeParmType>()->isParameterPack();
+ return getTypeForDecl()->castAs<TemplateTypeParmType>()->isParameterPack();
}
//===----------------------------------------------------------------------===//
@@ -704,12 +735,6 @@ FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
}
//===----------------------------------------------------------------------===//
-// TemplateDecl Implementation
-//===----------------------------------------------------------------------===//
-
-void TemplateDecl::anchor() {}
-
-//===----------------------------------------------------------------------===//
// ClassTemplateSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 6ef77b8aee68..3438c3aadc6b 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -85,8 +85,8 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
CE->getCastKind() == CK_UncheckedDerivedToBase) &&
E->getType()->isRecordType()) {
E = CE->getSubExpr();
- CXXRecordDecl *Derived
- = cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl());
+ auto *Derived =
+ cast<CXXRecordDecl>(E->getType()->castAs<RecordType>()->getDecl());
Adjustments.push_back(SubobjectAdjustment(CE, Derived));
continue;
}
@@ -185,6 +185,12 @@ bool Expr::isKnownToHaveBooleanValue() const {
return CO->getTrueExpr()->isKnownToHaveBooleanValue() &&
CO->getFalseExpr()->isKnownToHaveBooleanValue();
+ if (isa<ObjCBoolLiteralExpr>(E))
+ return true;
+
+ if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E))
+ return OVE->getSourceExpr()->isKnownToHaveBooleanValue();
+
return false;
}
@@ -2563,13 +2569,31 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
case CXXTemporaryObjectExprClass:
case CXXConstructExprClass: {
if (const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl()) {
- if (Type->hasAttr<WarnUnusedAttr>()) {
+ const auto *WarnURAttr = Type->getAttr<WarnUnusedResultAttr>();
+ if (Type->hasAttr<WarnUnusedAttr>() ||
+ (WarnURAttr && WarnURAttr->IsCXX11NoDiscard())) {
WarnE = this;
Loc = getBeginLoc();
R1 = getSourceRange();
return true;
}
}
+
+ const auto *CE = cast<CXXConstructExpr>(this);
+ if (const CXXConstructorDecl *Ctor = CE->getConstructor()) {
+ const auto *WarnURAttr = Ctor->getAttr<WarnUnusedResultAttr>();
+ if (WarnURAttr && WarnURAttr->IsCXX11NoDiscard()) {
+ WarnE = this;
+ Loc = getBeginLoc();
+ R1 = getSourceRange();
+
+ if (unsigned NumArgs = CE->getNumArgs())
+ R2 = SourceRange(CE->getArg(0)->getBeginLoc(),
+ CE->getArg(NumArgs - 1)->getEndLoc());
+ return true;
+ }
+ }
+
return false;
}
@@ -3181,7 +3205,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
if (ILE->getType()->isRecordType()) {
unsigned ElementNo = 0;
- RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = ILE->getType()->castAs<RecordType>()->getDecl();
for (const auto *Field : RD->fields()) {
// If this is a union, skip all the fields that aren't being initialized.
if (RD->isUnion() && ILE->getInitializedFieldInUnion() != Field)
@@ -3379,6 +3403,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case CXXUuidofExprClass:
case OpaqueValueExprClass:
case SourceLocExprClass:
+ case ConceptSpecializationExprClass:
// These never have a side-effect.
return false;
@@ -3448,6 +3473,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case ArrayInitLoopExprClass:
case ParenListExprClass:
case CXXPseudoDestructorExprClass:
+ case CXXRewrittenBinaryOperatorClass:
case CXXStdInitializerListExprClass:
case SubstNonTypeTemplateParmExprClass:
case MaterializeTemporaryExprClass:
@@ -3897,6 +3923,112 @@ bool Expr::refersToGlobalRegisterVar() const {
return false;
}
+bool Expr::isSameComparisonOperand(const Expr* E1, const Expr* E2) {
+ E1 = E1->IgnoreParens();
+ E2 = E2->IgnoreParens();
+
+ if (E1->getStmtClass() != E2->getStmtClass())
+ return false;
+
+ switch (E1->getStmtClass()) {
+ default:
+ return false;
+ case CXXThisExprClass:
+ return true;
+ case DeclRefExprClass: {
+ // DeclRefExpr without an ImplicitCastExpr can happen for integral
+ // template parameters.
+ const auto *DRE1 = cast<DeclRefExpr>(E1);
+ const auto *DRE2 = cast<DeclRefExpr>(E2);
+ return DRE1->isRValue() && DRE2->isRValue() &&
+ DRE1->getDecl() == DRE2->getDecl();
+ }
+ case ImplicitCastExprClass: {
+ // Peel off implicit casts.
+ while (true) {
+ const auto *ICE1 = dyn_cast<ImplicitCastExpr>(E1);
+ const auto *ICE2 = dyn_cast<ImplicitCastExpr>(E2);
+ if (!ICE1 || !ICE2)
+ return false;
+ if (ICE1->getCastKind() != ICE2->getCastKind())
+ return false;
+ E1 = ICE1->getSubExpr()->IgnoreParens();
+ E2 = ICE2->getSubExpr()->IgnoreParens();
+ // The final cast must be one of these types.
+ if (ICE1->getCastKind() == CK_LValueToRValue ||
+ ICE1->getCastKind() == CK_ArrayToPointerDecay ||
+ ICE1->getCastKind() == CK_FunctionToPointerDecay) {
+ break;
+ }
+ }
+
+ const auto *DRE1 = dyn_cast<DeclRefExpr>(E1);
+ const auto *DRE2 = dyn_cast<DeclRefExpr>(E2);
+ if (DRE1 && DRE2)
+ return declaresSameEntity(DRE1->getDecl(), DRE2->getDecl());
+
+ const auto *Ivar1 = dyn_cast<ObjCIvarRefExpr>(E1);
+ const auto *Ivar2 = dyn_cast<ObjCIvarRefExpr>(E2);
+ if (Ivar1 && Ivar2) {
+ return Ivar1->isFreeIvar() && Ivar2->isFreeIvar() &&
+ declaresSameEntity(Ivar1->getDecl(), Ivar2->getDecl());
+ }
+
+ const auto *Array1 = dyn_cast<ArraySubscriptExpr>(E1);
+ const auto *Array2 = dyn_cast<ArraySubscriptExpr>(E2);
+ if (Array1 && Array2) {
+ if (!isSameComparisonOperand(Array1->getBase(), Array2->getBase()))
+ return false;
+
+ auto Idx1 = Array1->getIdx();
+ auto Idx2 = Array2->getIdx();
+ const auto Integer1 = dyn_cast<IntegerLiteral>(Idx1);
+ const auto Integer2 = dyn_cast<IntegerLiteral>(Idx2);
+ if (Integer1 && Integer2) {
+ if (!llvm::APInt::isSameValue(Integer1->getValue(),
+ Integer2->getValue()))
+ return false;
+ } else {
+ if (!isSameComparisonOperand(Idx1, Idx2))
+ return false;
+ }
+
+ return true;
+ }
+
+ // Walk the MemberExpr chain.
+ while (isa<MemberExpr>(E1) && isa<MemberExpr>(E2)) {
+ const auto *ME1 = cast<MemberExpr>(E1);
+ const auto *ME2 = cast<MemberExpr>(E2);
+ if (!declaresSameEntity(ME1->getMemberDecl(), ME2->getMemberDecl()))
+ return false;
+ if (const auto *D = dyn_cast<VarDecl>(ME1->getMemberDecl()))
+ if (D->isStaticDataMember())
+ return true;
+ E1 = ME1->getBase()->IgnoreParenImpCasts();
+ E2 = ME2->getBase()->IgnoreParenImpCasts();
+ }
+
+ if (isa<CXXThisExpr>(E1) && isa<CXXThisExpr>(E2))
+ return true;
+
+ // A static member variable can end the MemberExpr chain with either
+ // a MemberExpr or a DeclRefExpr.
+ auto getAnyDecl = [](const Expr *E) -> const ValueDecl * {
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
+ return DRE->getDecl();
+ if (const auto *ME = dyn_cast<MemberExpr>(E))
+ return ME->getMemberDecl();
+ return nullptr;
+ };
+
+ const ValueDecl *VD1 = getAnyDecl(E1);
+ const ValueDecl *VD2 = getAnyDecl(E2);
+ return declaresSameEntity(VD1, VD2);
+ }
+ }
+}
+
/// isArrow - Return true if the base expression is a pointer to vector,
/// return false if the base expression is a vector.
bool ExtVectorElementExpr::isArrow() const {
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index b30f785ba8f5..904928bdf286 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -58,6 +58,76 @@ bool CXXOperatorCallExpr::isInfixBinaryOp() const {
}
}
+CXXRewrittenBinaryOperator::DecomposedForm
+CXXRewrittenBinaryOperator::getDecomposedForm() const {
+ DecomposedForm Result = {};
+ const Expr *E = getSemanticForm()->IgnoreImplicit();
+
+ // Remove an outer '!' if it exists (only happens for a '!=' rewrite).
+ bool SkippedNot = false;
+ if (auto *NotEq = dyn_cast<UnaryOperator>(E)) {
+ assert(NotEq->getOpcode() == UO_LNot);
+ E = NotEq->getSubExpr()->IgnoreImplicit();
+ SkippedNot = true;
+ }
+
+ // Decompose the outer binary operator.
+ if (auto *BO = dyn_cast<BinaryOperator>(E)) {
+ assert(!SkippedNot || BO->getOpcode() == BO_EQ);
+ Result.Opcode = SkippedNot ? BO_NE : BO->getOpcode();
+ Result.LHS = BO->getLHS();
+ Result.RHS = BO->getRHS();
+ Result.InnerBinOp = BO;
+ } else if (auto *BO = dyn_cast<CXXOperatorCallExpr>(E)) {
+ assert(!SkippedNot || BO->getOperator() == OO_EqualEqual);
+ assert(BO->isInfixBinaryOp());
+ switch (BO->getOperator()) {
+ case OO_Less: Result.Opcode = BO_LT; break;
+ case OO_LessEqual: Result.Opcode = BO_LE; break;
+ case OO_Greater: Result.Opcode = BO_GT; break;
+ case OO_GreaterEqual: Result.Opcode = BO_GE; break;
+ case OO_Spaceship: Result.Opcode = BO_Cmp; break;
+ case OO_EqualEqual: Result.Opcode = SkippedNot ? BO_NE : BO_EQ; break;
+ default: llvm_unreachable("unexpected binop in rewritten operator expr");
+ }
+ Result.LHS = BO->getArg(0);
+ Result.RHS = BO->getArg(1);
+ Result.InnerBinOp = BO;
+ } else {
+ llvm_unreachable("unexpected rewritten operator form");
+ }
+
+ // Put the operands in the right order for == and !=, and canonicalize the
+ // <=> subexpression onto the LHS for all other forms.
+ if (isReversed())
+ std::swap(Result.LHS, Result.RHS);
+
+ // If this isn't a spaceship rewrite, we're done.
+ if (Result.Opcode == BO_EQ || Result.Opcode == BO_NE)
+ return Result;
+
+ // Otherwise, we expect a <=> to now be on the LHS.
+ E = Result.LHS->IgnoreImplicit();
+ if (auto *BO = dyn_cast<BinaryOperator>(E)) {
+ assert(BO->getOpcode() == BO_Cmp);
+ Result.LHS = BO->getLHS();
+ Result.RHS = BO->getRHS();
+ Result.InnerBinOp = BO;
+ } else if (auto *BO = dyn_cast<CXXOperatorCallExpr>(E)) {
+ assert(BO->getOperator() == OO_Spaceship);
+ Result.LHS = BO->getArg(0);
+ Result.RHS = BO->getArg(1);
+ Result.InnerBinOp = BO;
+ } else {
+ llvm_unreachable("unexpected rewritten operator form");
+ }
+
+ // Put the comparison operands in the right order.
+ if (isReversed())
+ std::swap(Result.LHS, Result.RHS);
+ return Result;
+}
+
bool CXXTypeidExpr::isPotentiallyEvaluated() const {
if (isTypeOperand())
return false;
@@ -124,6 +194,8 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
if (ArraySize) {
if (Expr *SizeExpr = *ArraySize) {
+ if (SizeExpr->isValueDependent())
+ ExprBits.ValueDependent = true;
if (SizeExpr->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
if (SizeExpr->containsUnexpandedParameterPack())
@@ -134,6 +206,8 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
}
if (Initializer) {
+ if (Initializer->isValueDependent())
+ ExprBits.ValueDependent = true;
if (Initializer->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
if (Initializer->containsUnexpandedParameterPack())
@@ -143,6 +217,8 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
}
for (unsigned I = 0; I != PlacementArgs.size(); ++I) {
+ if (PlacementArgs[I]->isValueDependent())
+ ExprBits.ValueDependent = true;
if (PlacementArgs[I]->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
if (PlacementArgs[I]->containsUnexpandedParameterPack())
@@ -245,7 +321,7 @@ QualType CXXDeleteExpr::getDestroyedType() const {
if (ArgType->isDependentType() && !ArgType->isPointerType())
return QualType();
- return ArgType->getAs<PointerType>()->getPointeeType();
+ return ArgType->castAs<PointerType>()->getPointeeType();
}
// CXXPseudoDestructorExpr
@@ -651,6 +727,13 @@ Expr *CXXMemberCallExpr::getImplicitObjectArgument() const {
return nullptr;
}
+QualType CXXMemberCallExpr::getObjectType() const {
+ QualType Ty = getImplicitObjectArgument()->getType();
+ if (Ty->isPointerType())
+ Ty = Ty->getPointeeType();
+ return Ty;
+}
+
CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const {
if (const auto *MemExpr = dyn_cast<MemberExpr>(getCallee()->IgnoreParens()))
return cast<CXXMethodDecl>(MemExpr->getMemberDecl());
@@ -1205,6 +1288,11 @@ CXXMethodDecl *LambdaExpr::getCallOperator() const {
return Record->getLambdaCallOperator();
}
+FunctionTemplateDecl *LambdaExpr::getDependentCallOperator() const {
+ CXXRecordDecl *Record = getLambdaClass();
+ return Record->getDependentLambdaCallOperator();
+}
+
TemplateParameterList *LambdaExpr::getTemplateParameterList() const {
CXXRecordDecl *Record = getLambdaClass();
return Record->getGenericLambdaTemplateParameterList();
@@ -1494,11 +1582,8 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() {
// Otherwise the naming class must have been the base class.
else {
QualType BaseType = getBaseType().getNonReferenceType();
- if (isArrow()) {
- const auto *PT = BaseType->getAs<PointerType>();
- assert(PT && "base of arrow member access is not pointer");
- BaseType = PT->getPointeeType();
- }
+ if (isArrow())
+ BaseType = BaseType->castAs<PointerType>()->getPointeeType();
Record = BaseType->getAsCXXRecordDecl();
assert(Record && "base of member expression does not name record");
@@ -1665,3 +1750,82 @@ CUDAKernelCallExpr *CUDAKernelCallExpr::CreateEmpty(const ASTContext &Ctx,
alignof(CUDAKernelCallExpr));
return new (Mem) CUDAKernelCallExpr(NumArgs, Empty);
}
+
+ConceptSpecializationExpr::ConceptSpecializationExpr(ASTContext &C,
+ NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
+ SourceLocation ConceptNameLoc, NamedDecl *FoundDecl,
+ ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ArrayRef<TemplateArgument> ConvertedArgs, Optional<bool> IsSatisfied)
+ : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary,
+ /*TypeDependent=*/false,
+ // All the flags below are set in setTemplateArguments.
+ /*ValueDependent=*/!IsSatisfied.hasValue(),
+ /*InstantiationDependent=*/false,
+ /*ContainsUnexpandedParameterPacks=*/false),
+ NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc),
+ ConceptNameLoc(ConceptNameLoc), FoundDecl(FoundDecl),
+ NamedConcept(NamedConcept, IsSatisfied ? *IsSatisfied : true),
+ NumTemplateArgs(ConvertedArgs.size()) {
+
+ setTemplateArguments(ArgsAsWritten, ConvertedArgs);
+}
+
+ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
+ unsigned NumTemplateArgs)
+ : Expr(ConceptSpecializationExprClass, Empty),
+ NumTemplateArgs(NumTemplateArgs) { }
+
+void ConceptSpecializationExpr::setTemplateArguments(
+ const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ArrayRef<TemplateArgument> Converted) {
+ assert(Converted.size() == NumTemplateArgs);
+ assert(!this->ArgsAsWritten && "setTemplateArguments can only be used once");
+ this->ArgsAsWritten = ArgsAsWritten;
+ std::uninitialized_copy(Converted.begin(), Converted.end(),
+ getTrailingObjects<TemplateArgument>());
+ bool IsInstantiationDependent = false;
+ bool ContainsUnexpandedParameterPack = false;
+ for (const TemplateArgumentLoc& LocInfo : ArgsAsWritten->arguments()) {
+ if (LocInfo.getArgument().isInstantiationDependent())
+ IsInstantiationDependent = true;
+ if (LocInfo.getArgument().containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+ if (ContainsUnexpandedParameterPack && IsInstantiationDependent)
+ break;
+ }
+
+ // Currently guaranteed by the fact concepts can only be at namespace-scope.
+ assert(!NestedNameSpec ||
+ (!NestedNameSpec.getNestedNameSpecifier()->isInstantiationDependent() &&
+ !NestedNameSpec.getNestedNameSpecifier()
+ ->containsUnexpandedParameterPack()));
+ setInstantiationDependent(IsInstantiationDependent);
+ setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack);
+ assert((!isValueDependent() || isInstantiationDependent()) &&
+ "should not be value-dependent");
+}
+
+ConceptSpecializationExpr *
+ConceptSpecializationExpr::Create(ASTContext &C, NestedNameSpecifierLoc NNS,
+ SourceLocation TemplateKWLoc,
+ SourceLocation ConceptNameLoc,
+ NamedDecl *FoundDecl,
+ ConceptDecl *NamedConcept,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ArrayRef<TemplateArgument> ConvertedArgs,
+ Optional<bool> IsSatisfied) {
+ void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
+ ConvertedArgs.size()));
+ return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc,
+ ConceptNameLoc, FoundDecl,
+ NamedConcept, ArgsAsWritten,
+ ConvertedArgs, IsSatisfied);
+}
+
+ConceptSpecializationExpr *
+ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty,
+ unsigned NumTemplateArgs) {
+ void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
+ NumTemplateArgs));
+ return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs);
+}
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index c61ee703aca8..9dbf6fe9e0f0 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -192,6 +192,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::NoInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
case Expr::SourceLocExprClass:
+ case Expr::ConceptSpecializationExprClass:
return Cl::CL_PRValue;
case Expr::ConstantExprClass:
@@ -306,6 +307,10 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CUDAKernelCallExprClass:
return ClassifyUnnamed(Ctx, cast<CallExpr>(E)->getCallReturnType(Ctx));
+ case Expr::CXXRewrittenBinaryOperatorClass:
+ return ClassifyInternal(
+ Ctx, cast<CXXRewrittenBinaryOperator>(E)->getSemanticForm());
+
// __builtin_choose_expr is equivalent to the chosen expression.
case Expr::ChooseExprClass:
return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr());
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index f01b42e7ff76..42c746e60285 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -32,15 +32,21 @@
//
//===----------------------------------------------------------------------===//
+#include <cstring>
+#include <functional>
+#include "Interp/Context.h"
+#include "Interp/Frame.h"
+#include "Interp/State.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTLambda.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/CurrentSourceLocExprScope.h"
-#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/OSLog.h"
+#include "clang/AST/OptionalDiagnostic.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
@@ -51,8 +57,6 @@
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
-#include <cstring>
-#include <functional>
#define DEBUG_TYPE "exprconstant"
@@ -62,12 +66,10 @@ using llvm::APSInt;
using llvm::APFloat;
using llvm::Optional;
-static bool IsGlobalLValue(APValue::LValueBase B);
-
namespace {
struct LValue;
- struct CallStackFrame;
- struct EvalInfo;
+ class CallStackFrame;
+ class EvalInfo;
using SourceLocExprScopeGuard =
CurrentSourceLocExprScope::SourceLocExprScopeGuard;
@@ -94,6 +96,9 @@ namespace {
if (B.is<TypeInfoLValue>())
return B.getTypeInfoType();
+ if (B.is<DynamicAllocLValue>())
+ return B.getDynamicAllocType();
+
const Expr *Base = B.get<const Expr*>();
// For a materialized temporary, the type of the temporary we materialized
@@ -130,6 +135,14 @@ namespace {
return E.getAsBaseOrMember().getInt();
}
+ /// Given an expression, determine the type used to store the result of
+ /// evaluating that expression.
+ static QualType getStorageType(const ASTContext &Ctx, const Expr *E) {
+ if (E->isRValue())
+ return E->getType();
+ return Ctx.getLValueReferenceType(E->getType());
+ }
+
/// Given a CallExpr, try to get the alloc_size attribute. May return null.
static const AllocSizeAttr *getAllocSizeAttr(const CallExpr *CE) {
const FunctionDecl *Callee = CE->getDirectCallee();
@@ -222,12 +235,6 @@ namespace {
return MostDerivedLength;
}
- // The order of this enum is important for diagnostics.
- enum CheckSubobjectKind {
- CSK_Base, CSK_Derived, CSK_Field, CSK_ArrayToPointer, CSK_ArrayIndex,
- 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
@@ -480,7 +487,8 @@ namespace {
};
/// A stack frame in the constexpr call stack.
- struct CallStackFrame {
+ class CallStackFrame : public interp::Frame {
+ public:
EvalInfo &Info;
/// Parent - The caller of this stack frame.
@@ -573,7 +581,26 @@ namespace {
return 0;
}
- APValue &createTemporary(const void *Key, bool IsLifetimeExtended);
+ /// Allocate storage for an object of type T in this stack frame.
+ /// Populates LV with a handle to the created object. Key identifies
+ /// the temporary within the stack frame, and must not be reused without
+ /// bumping the temporary version number.
+ template<typename KeyT>
+ APValue &createTemporary(const KeyT *Key, QualType T,
+ bool IsLifetimeExtended, LValue &LV);
+
+ void describe(llvm::raw_ostream &OS) override;
+
+ Frame *getCaller() const override { return Caller; }
+ SourceLocation getCallLocation() const override { return CallLoc; }
+ const FunctionDecl *getCallee() const override { return Callee; }
+
+ bool isStdFunction() const {
+ for (const DeclContext *DC = Callee; DC; DC = DC->getParent())
+ if (DC->isStdNamespace())
+ return true;
+ return false;
+ }
};
/// Temporarily override 'this'.
@@ -591,71 +618,42 @@ namespace {
CallStackFrame &Frame;
const LValue *OldThis;
};
+}
- /// 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 = nullptr)
- : Diag(Diag) {}
-
- template<typename T>
- OptionalDiagnostic &operator<<(const T &v) {
- if (Diag)
- *Diag << v;
- return *this;
- }
-
- OptionalDiagnostic &operator<<(const APSInt &I) {
- if (Diag) {
- SmallVector<char, 32> Buffer;
- I.toString(Buffer);
- *Diag << StringRef(Buffer.data(), Buffer.size());
- }
- return *this;
- }
-
- OptionalDiagnostic &operator<<(const APFloat &F) {
- if (Diag) {
- // FIXME: Force the precision of the source value down so we don't
- // print digits which are usually useless (we don't really care here if
- // we truncate a digit by accident in edge cases). Ideally,
- // APFloat::toString would automatically print the shortest
- // representation which rounds to the correct value, but it's a bit
- // tricky to implement.
- unsigned precision =
- llvm::APFloat::semanticsPrecision(F.getSemantics());
- precision = (precision * 59 + 195) / 196;
- SmallVector<char, 32> Buffer;
- F.toString(Buffer, precision);
- *Diag << StringRef(Buffer.data(), Buffer.size());
- }
- return *this;
- }
-
- OptionalDiagnostic &operator<<(const APFixedPoint &FX) {
- if (Diag) {
- SmallVector<char, 32> Buffer;
- FX.toString(Buffer);
- *Diag << StringRef(Buffer.data(), Buffer.size());
- }
- return *this;
- }
- };
+static bool HandleDestruction(EvalInfo &Info, const Expr *E,
+ const LValue &This, QualType ThisType);
+static bool HandleDestruction(EvalInfo &Info, SourceLocation Loc,
+ APValue::LValueBase LVBase, APValue &Value,
+ QualType T);
+namespace {
/// A cleanup, and a flag indicating whether it is lifetime-extended.
class Cleanup {
llvm::PointerIntPair<APValue*, 1, bool> Value;
+ APValue::LValueBase Base;
+ QualType T;
public:
- Cleanup(APValue *Val, bool IsLifetimeExtended)
- : Value(Val, IsLifetimeExtended) {}
+ Cleanup(APValue *Val, APValue::LValueBase Base, QualType T,
+ bool IsLifetimeExtended)
+ : Value(Val, IsLifetimeExtended), Base(Base), T(T) {}
bool isLifetimeExtended() const { return Value.getInt(); }
- void endLifetime() {
+ bool endLifetime(EvalInfo &Info, bool RunDestructors) {
+ if (RunDestructors) {
+ SourceLocation Loc;
+ if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
+ Loc = VD->getLocation();
+ else if (const Expr *E = Base.dyn_cast<const Expr*>())
+ Loc = E->getExprLoc();
+ return HandleDestruction(Info, Loc, Base, *Value.getPointer(), T);
+ }
*Value.getPointer() = APValue();
+ return true;
+ }
+
+ bool hasSideEffect() {
+ return T.isDestructedType();
}
};
@@ -671,7 +669,13 @@ namespace {
return llvm::hash_combine(Obj.Base, Obj.Path);
}
};
- enum class ConstructionPhase { None, Bases, AfterBases };
+ enum class ConstructionPhase {
+ None,
+ Bases,
+ AfterBases,
+ Destroying,
+ DestroyingBases
+ };
}
namespace llvm {
@@ -693,6 +697,37 @@ template<> struct DenseMapInfo<ObjectUnderConstruction> {
}
namespace {
+ /// A dynamically-allocated heap object.
+ struct DynAlloc {
+ /// The value of this heap-allocated object.
+ APValue Value;
+ /// The allocating expression; used for diagnostics. Either a CXXNewExpr
+ /// or a CallExpr (the latter is for direct calls to operator new inside
+ /// std::allocator<T>::allocate).
+ const Expr *AllocExpr = nullptr;
+
+ enum Kind {
+ New,
+ ArrayNew,
+ StdAllocator
+ };
+
+ /// Get the kind of the allocation. This must match between allocation
+ /// and deallocation.
+ Kind getKind() const {
+ if (auto *NE = dyn_cast<CXXNewExpr>(AllocExpr))
+ return NE->isArray() ? ArrayNew : New;
+ assert(isa<CallExpr>(AllocExpr));
+ return StdAllocator;
+ }
+ };
+
+ struct DynAllocOrder {
+ bool operator()(DynamicAllocLValue L, DynamicAllocLValue R) const {
+ return L.getIndex() < R.getIndex();
+ }
+ };
+
/// 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
@@ -707,7 +742,8 @@ namespace {
/// 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 {
+ class EvalInfo : public interp::State {
+ public:
ASTContext &Ctx;
/// EvalStatus - Contains information about the evaluation.
@@ -727,6 +763,13 @@ namespace {
/// we will evaluate.
unsigned StepsLeft;
+ /// Force the use of the experimental new constant interpreter, bailing out
+ /// with an error if a feature is not supported.
+ bool ForceNewConstInterp;
+
+ /// Enable the experimental new constant interpreter.
+ bool EnableNewConstInterp;
+
/// BottomFrame - The frame in which evaluation started. This must be
/// initialized after CurrentCall and CallStackDepth.
CallStackFrame BottomFrame;
@@ -739,6 +782,15 @@ namespace {
/// evaluated, if any.
APValue::LValueBase EvaluatingDecl;
+ enum class EvaluatingDeclKind {
+ None,
+ /// We're evaluating the construction of EvaluatingDecl.
+ Ctor,
+ /// We're evaluating the destruction of EvaluatingDecl.
+ Dtor,
+ };
+ EvaluatingDeclKind IsEvaluatingDecl = EvaluatingDeclKind::None;
+
/// EvaluatingDeclValue - This is the value being constructed for the
/// declaration whose initializer is being evaluated, if any.
APValue *EvaluatingDeclValue;
@@ -747,6 +799,14 @@ namespace {
llvm::DenseMap<ObjectUnderConstruction, ConstructionPhase>
ObjectsUnderConstruction;
+ /// Current heap allocations, along with the location where each was
+ /// allocated. We use std::map here because we need stable addresses
+ /// for the stored APValues.
+ std::map<DynamicAllocLValue, DynAlloc, DynAllocOrder> HeapAllocs;
+
+ /// The number of heap allocations performed so far in this evaluation.
+ unsigned NumHeapAllocs = 0;
+
struct EvaluatingConstructorRAII {
EvalInfo &EI;
ObjectUnderConstruction Object;
@@ -768,9 +828,29 @@ namespace {
}
};
+ struct EvaluatingDestructorRAII {
+ EvalInfo &EI;
+ ObjectUnderConstruction Object;
+ bool DidInsert;
+ EvaluatingDestructorRAII(EvalInfo &EI, ObjectUnderConstruction Object)
+ : EI(EI), Object(Object) {
+ DidInsert = EI.ObjectsUnderConstruction
+ .insert({Object, ConstructionPhase::Destroying})
+ .second;
+ }
+ void startedDestroyingBases() {
+ EI.ObjectsUnderConstruction[Object] =
+ ConstructionPhase::DestroyingBases;
+ }
+ ~EvaluatingDestructorRAII() {
+ if (DidInsert)
+ EI.ObjectsUnderConstruction.erase(Object);
+ }
+ };
+
ConstructionPhase
- isEvaluatingConstructor(APValue::LValueBase Base,
- ArrayRef<APValue::LValuePathEntry> Path) {
+ isEvaluatingCtorDtor(APValue::LValueBase Base,
+ ArrayRef<APValue::LValuePathEntry> Path) {
return ObjectsUnderConstruction.lookup({Base, Path});
}
@@ -794,76 +874,74 @@ namespace {
/// constant value.
bool InConstantContext;
+ /// Whether we're checking that an expression is a potential constant
+ /// expression. If so, do not fail on constructs that could become constant
+ /// later on (such as a use of an undefined global).
+ bool CheckingPotentialConstantExpression = false;
+
+ /// Whether we're checking for an expression that has undefined behavior.
+ /// If so, we will produce warnings if we encounter an operation that is
+ /// always undefined.
+ bool CheckingForUndefinedBehavior = false;
+
enum EvaluationMode {
/// Evaluate as a constant expression. Stop if we find that the expression
/// is not a constant expression.
EM_ConstantExpression,
- /// Evaluate as a potential constant expression. Keep going if we hit a
- /// construct that we can't evaluate yet (because we don't yet know the
- /// value of something) but stop if we hit something that could never be
- /// a constant expression.
- EM_PotentialConstantExpression,
+ /// Evaluate as a constant expression. Stop if we find that the expression
+ /// is not a constant expression. Some expressions can be retried in the
+ /// optimizer if we don't constant fold them here, but in an unevaluated
+ /// context we try to fold them immediately since the optimizer never
+ /// gets a chance to look at it.
+ EM_ConstantExpressionUnevaluated,
/// Fold the expression to a constant. Stop if we hit a side-effect that
/// we can't model.
EM_ConstantFold,
- /// Evaluate the expression looking for integer overflow and similar
- /// issues. Don't worry about side-effects, and try to visit all
- /// subexpressions.
- EM_EvaluateForOverflow,
-
/// Evaluate in any way we know how. Don't worry about side-effects that
/// can't be modeled.
EM_IgnoreSideEffects,
-
- /// Evaluate as a constant expression. Stop if we find that the expression
- /// is not a constant expression. Some expressions can be retried in the
- /// optimizer if we don't constant fold them here, but in an unevaluated
- /// context we try to fold them immediately since the optimizer never
- /// gets a chance to look at it.
- EM_ConstantExpressionUnevaluated,
-
- /// Evaluate as a potential constant expression. Keep going if we hit a
- /// construct that we can't evaluate yet (because we don't yet know the
- /// value of something) but stop if we hit something that could never be
- /// a constant expression. Some expressions can be retried in the
- /// optimizer if we don't constant fold them here, but in an unevaluated
- /// context we try to fold them immediately since the optimizer never
- /// gets a chance to look at it.
- EM_PotentialConstantExpressionUnevaluated,
} EvalMode;
/// Are we checking whether the expression is a potential constant
/// expression?
- bool checkingPotentialConstantExpression() const {
- return EvalMode == EM_PotentialConstantExpression ||
- EvalMode == EM_PotentialConstantExpressionUnevaluated;
+ bool checkingPotentialConstantExpression() const override {
+ return CheckingPotentialConstantExpression;
}
/// Are we checking an expression for overflow?
// FIXME: We should check for any kind of undefined or suspicious behavior
// in such constructs, not just overflow.
- bool checkingForOverflow() { return EvalMode == EM_EvaluateForOverflow; }
+ bool checkingForUndefinedBehavior() const override {
+ return CheckingForUndefinedBehavior;
+ }
EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode)
- : Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr),
- CallStackDepth(0), NextCallIndex(1),
- StepsLeft(getLangOpts().ConstexprStepLimit),
- BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr),
- EvaluatingDecl((const ValueDecl *)nullptr),
- EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
- HasFoldFailureDiagnostic(false),
- InConstantContext(false), EvalMode(Mode) {}
-
- void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
+ : Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr),
+ CallStackDepth(0), NextCallIndex(1),
+ StepsLeft(getLangOpts().ConstexprStepLimit),
+ ForceNewConstInterp(getLangOpts().ForceNewConstInterp),
+ EnableNewConstInterp(ForceNewConstInterp ||
+ getLangOpts().EnableNewConstInterp),
+ BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr),
+ EvaluatingDecl((const ValueDecl *)nullptr),
+ EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
+ HasFoldFailureDiagnostic(false), InConstantContext(false),
+ EvalMode(Mode) {}
+
+ ~EvalInfo() {
+ discardCleanups();
+ }
+
+ void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value,
+ EvaluatingDeclKind EDK = EvaluatingDeclKind::Ctor) {
EvaluatingDecl = Base;
+ IsEvaluatingDecl = EDK;
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.
@@ -906,133 +984,124 @@ namespace {
return true;
}
- 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;
+ APValue *createHeapAlloc(const Expr *E, QualType T, LValue &LV);
+
+ Optional<DynAlloc*> lookupDynamicAlloc(DynamicAllocLValue DA) {
+ Optional<DynAlloc*> Result;
+ auto It = HeapAllocs.find(DA);
+ if (It != HeapAllocs.end())
+ Result = &It->second;
+ return Result;
}
- /// Add notes containing a call stack to the current point of evaluation.
- void addCallStack(unsigned Limit);
+ /// Information about a stack frame for std::allocator<T>::[de]allocate.
+ struct StdAllocatorCaller {
+ unsigned FrameIndex;
+ QualType ElemType;
+ explicit operator bool() const { return FrameIndex != 0; };
+ };
- private:
- OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId,
- unsigned ExtraNotes, bool IsCCEDiag) {
+ StdAllocatorCaller getStdAllocatorCaller(StringRef FnName) const {
+ for (const CallStackFrame *Call = CurrentCall; Call != &BottomFrame;
+ Call = Call->Caller) {
+ const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Call->Callee);
+ if (!MD)
+ continue;
+ const IdentifierInfo *FnII = MD->getIdentifier();
+ if (!FnII || !FnII->isStr(FnName))
+ continue;
- if (EvalStatus.Diag) {
- // If we have a prior diagnostic, it will be noting that the expression
- // isn't a constant expression. This diagnostic is more important,
- // unless we require this evaluation to produce a constant expression.
- //
- // FIXME: We might want to show both diagnostics to the user in
- // EM_ConstantFold mode.
- if (!EvalStatus.Diag->empty()) {
- switch (EvalMode) {
- case EM_ConstantFold:
- case EM_IgnoreSideEffects:
- case EM_EvaluateForOverflow:
- if (!HasFoldFailureDiagnostic)
- break;
- // We've already failed to fold something. Keep that diagnostic.
- LLVM_FALLTHROUGH;
- case EM_ConstantExpression:
- case EM_PotentialConstantExpression:
- case EM_ConstantExpressionUnevaluated:
- case EM_PotentialConstantExpressionUnevaluated:
- HasActiveDiagnostic = false;
- return OptionalDiagnostic();
- }
- }
+ const auto *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
+ if (!CTSD)
+ continue;
- unsigned CallStackNotes = CallStackDepth - 1;
- unsigned Limit = Ctx.getDiagnostics().getConstexprBacktraceLimit();
- if (Limit)
- CallStackNotes = std::min(CallStackNotes, Limit + 1);
- if (checkingPotentialConstantExpression())
- CallStackNotes = 0;
-
- HasActiveDiagnostic = true;
- HasFoldFailureDiagnostic = !IsCCEDiag;
- EvalStatus.Diag->clear();
- EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes);
- addDiag(Loc, DiagId);
- if (!checkingPotentialConstantExpression())
- addCallStack(Limit);
- return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second);
+ const IdentifierInfo *ClassII = CTSD->getIdentifier();
+ const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
+ if (CTSD->isInStdNamespace() && ClassII &&
+ ClassII->isStr("allocator") && TAL.size() >= 1 &&
+ TAL[0].getKind() == TemplateArgument::Type)
+ return {Call->Index, TAL[0].getAsType()};
}
- HasActiveDiagnostic = false;
- return OptionalDiagnostic();
- }
- public:
- // Diagnose that the evaluation could not be folded (FF => FoldFailure)
- OptionalDiagnostic
- FFDiag(SourceLocation Loc,
- diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
- unsigned ExtraNotes = 0) {
- return Diag(Loc, DiagId, ExtraNotes, false);
- }
- OptionalDiagnostic FFDiag(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, /*IsCCEDiag*/false);
- HasActiveDiagnostic = false;
- return OptionalDiagnostic();
+ return {};
+ }
+
+ void performLifetimeExtension() {
+ // Disable the cleanups for lifetime-extended temporaries.
+ CleanupStack.erase(
+ std::remove_if(CleanupStack.begin(), CleanupStack.end(),
+ [](Cleanup &C) { return C.isLifetimeExtended(); }),
+ CleanupStack.end());
+ }
+
+ /// Throw away any remaining cleanups at the end of evaluation. If any
+ /// cleanups would have had a side-effect, note that as an unmodeled
+ /// side-effect and return false. Otherwise, return true.
+ bool discardCleanups() {
+ for (Cleanup &C : CleanupStack)
+ if (C.hasSideEffect())
+ if (!noteSideEffect())
+ return false;
+ return true;
}
- /// Diagnose that the evaluation does not produce a C++11 core constant
- /// expression.
- ///
- /// FIXME: Stop evaluating if we're in EM_ConstantExpression or
- /// EM_PotentialConstantExpression mode and we produce one of these.
- OptionalDiagnostic CCEDiag(SourceLocation Loc, diag::kind DiagId
- = diag::note_invalid_subexpr_in_const_expr,
- unsigned ExtraNotes = 0) {
- // Don't override a previous diagnostic. Don't bother collecting
- // diagnostics if we're evaluating for overflow.
- if (!EvalStatus.Diag || !EvalStatus.Diag->empty()) {
- HasActiveDiagnostic = false;
- return OptionalDiagnostic();
+ private:
+ interp::Frame *getCurrentFrame() override { return CurrentCall; }
+ const interp::Frame *getBottomFrame() const override { return &BottomFrame; }
+
+ bool hasActiveDiagnostic() override { return HasActiveDiagnostic; }
+ void setActiveDiagnostic(bool Flag) override { HasActiveDiagnostic = Flag; }
+
+ void setFoldFailureDiagnostic(bool Flag) override {
+ HasFoldFailureDiagnostic = Flag;
+ }
+
+ Expr::EvalStatus &getEvalStatus() const override { return EvalStatus; }
+
+ ASTContext &getCtx() const override { return Ctx; }
+
+ // If we have a prior diagnostic, it will be noting that the expression
+ // isn't a constant expression. This diagnostic is more important,
+ // unless we require this evaluation to produce a constant expression.
+ //
+ // FIXME: We might want to show both diagnostics to the user in
+ // EM_ConstantFold mode.
+ bool hasPriorDiagnostic() override {
+ if (!EvalStatus.Diag->empty()) {
+ switch (EvalMode) {
+ case EM_ConstantFold:
+ case EM_IgnoreSideEffects:
+ if (!HasFoldFailureDiagnostic)
+ break;
+ // We've already failed to fold something. Keep that diagnostic.
+ LLVM_FALLTHROUGH;
+ case EM_ConstantExpression:
+ case EM_ConstantExpressionUnevaluated:
+ setActiveDiagnostic(false);
+ return true;
+ }
}
- return Diag(Loc, DiagId, ExtraNotes, true);
- }
- OptionalDiagnostic CCEDiag(const Expr *E, diag::kind DiagId
- = diag::note_invalid_subexpr_in_const_expr,
- unsigned ExtraNotes = 0) {
- return CCEDiag(E->getExprLoc(), 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));
+ return false;
}
- /// 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());
- }
- }
+ unsigned getCallStackDepth() override { return CallStackDepth; }
+ public:
/// Should we continue evaluation after encountering a side-effect that we
/// couldn't model?
bool keepEvaluatingAfterSideEffect() {
switch (EvalMode) {
- case EM_PotentialConstantExpression:
- case EM_PotentialConstantExpressionUnevaluated:
- case EM_EvaluateForOverflow:
case EM_IgnoreSideEffects:
return true;
case EM_ConstantExpression:
case EM_ConstantExpressionUnevaluated:
case EM_ConstantFold:
- return false;
+ // By default, assume any side effect might be valid in some other
+ // evaluation of this expression from a different context.
+ return checkingPotentialConstantExpression() ||
+ checkingForUndefinedBehavior();
}
llvm_unreachable("Missed EvalMode case");
}
@@ -1047,16 +1116,13 @@ namespace {
/// Should we continue evaluation after encountering undefined behavior?
bool keepEvaluatingAfterUndefinedBehavior() {
switch (EvalMode) {
- case EM_EvaluateForOverflow:
case EM_IgnoreSideEffects:
case EM_ConstantFold:
return true;
- case EM_PotentialConstantExpression:
- case EM_PotentialConstantExpressionUnevaluated:
case EM_ConstantExpression:
case EM_ConstantExpressionUnevaluated:
- return false;
+ return checkingForUndefinedBehavior();
}
llvm_unreachable("Missed EvalMode case");
}
@@ -1064,28 +1130,24 @@ namespace {
/// Note that we hit something that was technically undefined behavior, but
/// that we can evaluate past it (such as signed overflow or floating-point
/// division by zero.)
- bool noteUndefinedBehavior() {
+ bool noteUndefinedBehavior() override {
EvalStatus.HasUndefinedBehavior = true;
return keepEvaluatingAfterUndefinedBehavior();
}
/// Should we continue evaluation as much as possible after encountering a
/// construct which can't be reduced to a value?
- bool keepEvaluatingAfterFailure() {
+ bool keepEvaluatingAfterFailure() const override {
if (!StepsLeft)
return false;
switch (EvalMode) {
- case EM_PotentialConstantExpression:
- case EM_PotentialConstantExpressionUnevaluated:
- case EM_EvaluateForOverflow:
- return true;
-
case EM_ConstantExpression:
case EM_ConstantExpressionUnevaluated:
case EM_ConstantFold:
case EM_IgnoreSideEffects:
- return false;
+ return checkingPotentialConstantExpression() ||
+ checkingForUndefinedBehavior();
}
llvm_unreachable("Missed EvalMode case");
}
@@ -1142,9 +1204,7 @@ namespace {
Info.EvalStatus.Diag->empty() &&
!Info.EvalStatus.HasSideEffects),
OldMode(Info.EvalMode) {
- if (Enabled &&
- (Info.EvalMode == EvalInfo::EM_ConstantExpression ||
- Info.EvalMode == EvalInfo::EM_ConstantExpressionUnevaluated))
+ if (Enabled)
Info.EvalMode = EvalInfo::EM_ConstantFold;
}
void keepDiagnostics() { Enabled = false; }
@@ -1163,8 +1223,7 @@ namespace {
EvalInfo::EvaluationMode OldMode;
explicit IgnoreSideEffectsRAII(EvalInfo &Info)
: Info(Info), OldMode(Info.EvalMode) {
- if (!Info.checkingPotentialConstantExpression())
- Info.EvalMode = EvalInfo::EM_IgnoreSideEffects;
+ Info.EvalMode = EvalInfo::EM_IgnoreSideEffects;
}
~IgnoreSideEffectsRAII() { Info.EvalMode = OldMode; }
@@ -1230,29 +1289,45 @@ namespace {
// temporaries created in different iterations of a loop.
Info.CurrentCall->pushTempVersion();
}
+ bool destroy(bool RunDestructors = true) {
+ bool OK = cleanup(Info, RunDestructors, OldStackSize);
+ OldStackSize = -1U;
+ return OK;
+ }
~ScopeRAII() {
+ if (OldStackSize != -1U)
+ destroy(false);
// Body moved to a static method to encourage the compiler to inline away
// instances of this class.
- cleanup(Info, OldStackSize);
Info.CurrentCall->popTempVersion();
}
private:
- static void cleanup(EvalInfo &Info, unsigned OldStackSize) {
- unsigned NewEnd = OldStackSize;
- for (unsigned I = OldStackSize, N = Info.CleanupStack.size();
- I != N; ++I) {
- if (IsFullExpression && Info.CleanupStack[I].isLifetimeExtended()) {
- // Full-expression cleanup of a lifetime-extended temporary: nothing
- // to do, just move this cleanup to the right place in the stack.
- std::swap(Info.CleanupStack[I], Info.CleanupStack[NewEnd]);
- ++NewEnd;
- } else {
- // End the lifetime of the object.
- Info.CleanupStack[I].endLifetime();
+ static bool cleanup(EvalInfo &Info, bool RunDestructors,
+ unsigned OldStackSize) {
+ assert(OldStackSize <= Info.CleanupStack.size() &&
+ "running cleanups out of order?");
+
+ // Run all cleanups for a block scope, and non-lifetime-extended cleanups
+ // for a full-expression scope.
+ bool Success = true;
+ for (unsigned I = Info.CleanupStack.size(); I > OldStackSize; --I) {
+ if (!(IsFullExpression &&
+ Info.CleanupStack[I - 1].isLifetimeExtended())) {
+ if (!Info.CleanupStack[I - 1].endLifetime(Info, RunDestructors)) {
+ Success = false;
+ break;
+ }
}
}
- Info.CleanupStack.erase(Info.CleanupStack.begin() + NewEnd,
- Info.CleanupStack.end());
+
+ // Compact lifetime-extended cleanups.
+ auto NewEnd = Info.CleanupStack.begin() + OldStackSize;
+ if (IsFullExpression)
+ NewEnd =
+ std::remove_if(NewEnd, Info.CleanupStack.end(),
+ [](Cleanup &C) { return !C.isLifetimeExtended(); });
+ Info.CleanupStack.erase(NewEnd, Info.CleanupStack.end());
+ return Success;
}
};
typedef ScopeRAII<false> BlockScopeRAII;
@@ -1312,74 +1387,14 @@ CallStackFrame::~CallStackFrame() {
Info.CurrentCall = Caller;
}
-APValue &CallStackFrame::createTemporary(const void *Key,
- bool IsLifetimeExtended) {
- unsigned Version = Info.CurrentCall->getTempVersion();
- APValue &Result = Temporaries[MapKeyTy(Key, Version)];
- assert(Result.isAbsent() && "temporary created multiple times");
- Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended));
- return Result;
+static bool isRead(AccessKinds AK) {
+ return AK == AK_Read || AK == AK_ReadObjectRepresentation;
}
-static void describeCall(CallStackFrame *Frame, raw_ostream &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;
- }
-
- // Use a different note for an inheriting constructor, because from the
- // user's perspective it's not really a function at all.
- if (auto *CD = dyn_cast_or_null<CXXConstructorDecl>(Frame->Callee)) {
- if (CD->isInheritingConstructor()) {
- addDiag(Frame->CallLoc, diag::note_constexpr_inherited_ctor_call_here)
- << CD->getParent();
- continue;
- }
- }
-
- SmallVector<char, 128> Buffer;
- llvm::raw_svector_ostream Out(Buffer);
- describeCall(Frame, Out);
- addDiag(Frame->CallLoc, diag::note_constexpr_call_here) << Out.str();
- }
-}
-
-/// Kinds of access we can perform on an object, for diagnostics. Note that
-/// we consider a member function call to be a kind of access, even though
-/// it is not formally an access of the object, because it has (largely) the
-/// same set of semantic restrictions.
-enum AccessKinds {
- AK_Read,
- AK_Assign,
- AK_Increment,
- AK_Decrement,
- AK_MemberCall,
- AK_DynamicCast,
- AK_TypeId,
-};
-
static bool isModification(AccessKinds AK) {
switch (AK) {
case AK_Read:
+ case AK_ReadObjectRepresentation:
case AK_MemberCall:
case AK_DynamicCast:
case AK_TypeId:
@@ -1387,14 +1402,20 @@ static bool isModification(AccessKinds AK) {
case AK_Assign:
case AK_Increment:
case AK_Decrement:
+ case AK_Construct:
+ case AK_Destroy:
return true;
}
llvm_unreachable("unknown access kind");
}
+static bool isAnyAccess(AccessKinds AK) {
+ return isRead(AK) || isModification(AK);
+}
+
/// Is this an access per the C++ definition?
static bool isFormalAccess(AccessKinds AK) {
- return AK == AK_Read || isModification(AK);
+ return isAnyAccess(AK) && AK != AK_Construct && AK != AK_Destroy;
}
namespace {
@@ -1490,9 +1511,10 @@ namespace {
IsNullPtr = false;
}
- void setNull(QualType PointerTy, uint64_t TargetVal) {
+ void setNull(ASTContext &Ctx, QualType PointerTy) {
Base = (Expr *)nullptr;
- Offset = CharUnits::fromQuantity(TargetVal);
+ Offset =
+ CharUnits::fromQuantity(Ctx.getTargetNullPointerValue(PointerTy));
InvalidBase = false;
Designator = SubobjectDesignator(PointerTy->getPointeeType());
IsNullPtr = true;
@@ -1502,6 +1524,12 @@ namespace {
set(B, true);
}
+ std::string toString(ASTContext &Ctx, QualType T) const {
+ APValue Printable;
+ moveInto(Printable);
+ return Printable.getAsString(Ctx, T);
+ }
+
private:
// Check that this LValue is not based on a null pointer. If it is, produce
// a diagnostic and mark the designator as invalid.
@@ -1724,15 +1752,6 @@ static bool EvaluateFixedPoint(const Expr *E, APFixedPoint &Result,
// Misc utilities
//===----------------------------------------------------------------------===//
-/// A helper function to create a temporary and set an LValue.
-template <class KeyTy>
-static APValue &createTemporary(const KeyTy *Key, bool IsLifetimeExtended,
- LValue &LV, CallStackFrame &Frame) {
- LV.set({Key, Frame.Info.CurrentCall->Index,
- Frame.Info.CurrentCall->getTempVersion()});
- return Frame.createTemporary(Key, IsLifetimeExtended);
-}
-
/// Negate an APSInt in place, converting it to a signed form if necessary, and
/// preserving its value (by extending by up to one bit as needed).
static void negateAsSigned(APSInt &Int) {
@@ -1743,37 +1762,74 @@ static void negateAsSigned(APSInt &Int) {
Int = -Int;
}
+template<typename KeyT>
+APValue &CallStackFrame::createTemporary(const KeyT *Key, QualType T,
+ bool IsLifetimeExtended, LValue &LV) {
+ unsigned Version = getTempVersion();
+ APValue::LValueBase Base(Key, Index, Version);
+ LV.set(Base);
+ APValue &Result = Temporaries[MapKeyTy(Key, Version)];
+ assert(Result.isAbsent() && "temporary created multiple times");
+
+ // If we're creating a temporary immediately in the operand of a speculative
+ // evaluation, don't register a cleanup to be run outside the speculative
+ // evaluation context, since we won't actually be able to initialize this
+ // object.
+ if (Index <= Info.SpeculativeEvaluationDepth) {
+ if (T.isDestructedType())
+ Info.noteSideEffect();
+ } else {
+ Info.CleanupStack.push_back(Cleanup(&Result, Base, T, IsLifetimeExtended));
+ }
+ return Result;
+}
+
+APValue *EvalInfo::createHeapAlloc(const Expr *E, QualType T, LValue &LV) {
+ if (NumHeapAllocs > DynamicAllocLValue::getMaxIndex()) {
+ FFDiag(E, diag::note_constexpr_heap_alloc_limit_exceeded);
+ return nullptr;
+ }
+
+ DynamicAllocLValue DA(NumHeapAllocs++);
+ LV.set(APValue::LValueBase::getDynamicAlloc(DA, T));
+ auto Result = HeapAllocs.emplace(std::piecewise_construct,
+ std::forward_as_tuple(DA), std::tuple<>());
+ assert(Result.second && "reused a heap alloc index?");
+ Result.first->second.AllocExpr = E;
+ return &Result.first->second.Value;
+}
+
/// Produce a string describing the given constexpr call.
-static void describeCall(CallStackFrame *Frame, raw_ostream &Out) {
+void CallStackFrame::describe(raw_ostream &Out) {
unsigned ArgIndex = 0;
- bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) &&
- !isa<CXXConstructorDecl>(Frame->Callee) &&
- cast<CXXMethodDecl>(Frame->Callee)->isInstance();
+ bool IsMemberCall = isa<CXXMethodDecl>(Callee) &&
+ !isa<CXXConstructorDecl>(Callee) &&
+ cast<CXXMethodDecl>(Callee)->isInstance();
if (!IsMemberCall)
- Out << *Frame->Callee << '(';
+ Out << *Callee << '(';
- if (Frame->This && IsMemberCall) {
+ if (This && IsMemberCall) {
APValue Val;
- Frame->This->moveInto(Val);
- Val.printPretty(Out, Frame->Info.Ctx,
- Frame->This->Designator.MostDerivedType);
+ This->moveInto(Val);
+ Val.printPretty(Out, Info.Ctx,
+ This->Designator.MostDerivedType);
// FIXME: Add parens around Val if needed.
- Out << "->" << *Frame->Callee << '(';
+ Out << "->" << *Callee << '(';
IsMemberCall = false;
}
- for (FunctionDecl::param_const_iterator I = Frame->Callee->param_begin(),
- E = Frame->Callee->param_end(); I != E; ++I, ++ArgIndex) {
+ for (FunctionDecl::param_const_iterator I = Callee->param_begin(),
+ E = 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());
+ const APValue &Arg = Arguments[ArgIndex];
+ Arg.printPretty(Out, Info.Ctx, Param->getType());
if (ArgIndex == 0 && IsMemberCall)
- Out << "->" << *Frame->Callee << '(';
+ Out << "->" << *Callee << '(';
}
Out << ')';
@@ -1813,7 +1869,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
return isa<FunctionDecl>(D);
}
- if (B.is<TypeInfoLValue>())
+ if (B.is<TypeInfoLValue>() || B.is<DynamicAllocLValue>())
return true;
const Expr *E = B.get<const Expr*>();
@@ -1912,15 +1968,39 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
Info.Note(VD->getLocation(), diag::note_declared_at);
else if (const Expr *E = Base.dyn_cast<const Expr*>())
Info.Note(E->getExprLoc(), diag::note_constexpr_temporary_here);
+ else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) {
+ // FIXME: Produce a note for dangling pointers too.
+ if (Optional<DynAlloc*> Alloc = Info.lookupDynamicAlloc(DA))
+ Info.Note((*Alloc)->AllocExpr->getExprLoc(),
+ diag::note_constexpr_dynamic_alloc_here);
+ }
// We have no information to show for a typeid(T) object.
}
+enum class CheckEvaluationResultKind {
+ ConstantExpression,
+ FullyInitialized,
+};
+
+/// Materialized temporaries that we've already checked to determine if they're
+/// initializsed by a constant expression.
+using CheckedTemporaries =
+ llvm::SmallPtrSet<const MaterializeTemporaryExpr *, 8>;
+
+static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
+ EvalInfo &Info, SourceLocation DiagLoc,
+ QualType Type, const APValue &Value,
+ Expr::ConstExprUsage Usage,
+ SourceLocation SubobjectLoc,
+ CheckedTemporaries &CheckedTemps);
+
/// 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,
- Expr::ConstExprUsage Usage) {
+ Expr::ConstExprUsage Usage,
+ CheckedTemporaries &CheckedTemps) {
bool IsReferenceType = Type->isReferenceType();
APValue::LValueBase Base = LVal.getLValueBase();
@@ -1946,14 +2026,23 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
LVal.getLValueCallIndex() == 0) &&
"have call index for global lvalue");
+ if (Base.is<DynamicAllocLValue>()) {
+ Info.FFDiag(Loc, diag::note_constexpr_dynamic_alloc)
+ << IsReferenceType << !Designator.Entries.empty();
+ NoteLValueLocation(Info, Base);
+ return false;
+ }
+
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
if (const VarDecl *Var = dyn_cast<const VarDecl>(VD)) {
// Check if this is a thread-local variable.
if (Var->getTLSKind())
+ // FIXME: Diagnostic!
return false;
// A dllimport variable never acts like a constant.
if (Usage == Expr::EvaluateForCodeGen && Var->hasAttr<DLLImportAttr>())
+ // FIXME: Diagnostic!
return false;
}
if (const auto *FD = dyn_cast<const FunctionDecl>(VD)) {
@@ -1969,6 +2058,25 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
// perform initialization with the address of the thunk.
if (Info.getLangOpts().CPlusPlus && Usage == Expr::EvaluateForCodeGen &&
FD->hasAttr<DLLImportAttr>())
+ // FIXME: Diagnostic!
+ return false;
+ }
+ } else if (const auto *MTE = dyn_cast_or_null<MaterializeTemporaryExpr>(
+ Base.dyn_cast<const Expr *>())) {
+ if (CheckedTemps.insert(MTE).second) {
+ QualType TempType = getType(Base);
+ if (TempType.isDestructedType()) {
+ Info.FFDiag(MTE->getExprLoc(),
+ diag::note_constexpr_unsupported_tempoarary_nontrivial_dtor)
+ << TempType;
+ return false;
+ }
+
+ APValue *V = Info.Ctx.getMaterializedTemporaryValue(MTE, false);
+ assert(V && "evasluation result refers to uninitialised temporary");
+ if (!CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
+ Info, MTE->getExprLoc(), TempType, *V,
+ Usage, SourceLocation(), CheckedTemps))
return false;
}
}
@@ -2043,14 +2151,12 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
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,
- Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen,
- SourceLocation SubobjectLoc = SourceLocation()) {
+static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
+ EvalInfo &Info, SourceLocation DiagLoc,
+ QualType Type, const APValue &Value,
+ Expr::ConstExprUsage Usage,
+ SourceLocation SubobjectLoc,
+ CheckedTemporaries &CheckedTemps) {
if (!Value.hasValue()) {
Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized)
<< true << Type;
@@ -2070,30 +2176,31 @@ CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type,
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), Usage,
- SubobjectLoc))
+ if (!CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
+ Value.getArrayInitializedElt(I), Usage,
+ SubobjectLoc, CheckedTemps))
return false;
}
if (!Value.hasArrayFiller())
return true;
- return CheckConstantExpression(Info, DiagLoc, EltTy, Value.getArrayFiller(),
- Usage, SubobjectLoc);
+ return CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
+ Value.getArrayFiller(), Usage, SubobjectLoc,
+ CheckedTemps);
}
if (Value.isUnion() && Value.getUnionField()) {
- return CheckConstantExpression(Info, DiagLoc,
- Value.getUnionField()->getType(),
- Value.getUnionValue(), Usage,
- Value.getUnionField()->getLocation());
+ return CheckEvaluationResult(
+ CERK, Info, DiagLoc, Value.getUnionField()->getType(),
+ Value.getUnionValue(), Usage, Value.getUnionField()->getLocation(),
+ CheckedTemps);
}
if (Value.isStruct()) {
RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
unsigned BaseIndex = 0;
for (const CXXBaseSpecifier &BS : CD->bases()) {
- if (!CheckConstantExpression(Info, DiagLoc, BS.getType(),
- Value.getStructBase(BaseIndex), Usage,
- BS.getBeginLoc()))
+ if (!CheckEvaluationResult(CERK, Info, DiagLoc, BS.getType(),
+ Value.getStructBase(BaseIndex), Usage,
+ BS.getBeginLoc(), CheckedTemps))
return false;
++BaseIndex;
}
@@ -2102,26 +2209,66 @@ CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type,
if (I->isUnnamedBitfield())
continue;
- if (!CheckConstantExpression(Info, DiagLoc, I->getType(),
- Value.getStructField(I->getFieldIndex()),
- Usage, I->getLocation()))
+ if (!CheckEvaluationResult(CERK, Info, DiagLoc, I->getType(),
+ Value.getStructField(I->getFieldIndex()),
+ Usage, I->getLocation(), CheckedTemps))
return false;
}
}
- if (Value.isLValue()) {
+ if (Value.isLValue() &&
+ CERK == CheckEvaluationResultKind::ConstantExpression) {
LValue LVal;
LVal.setFrom(Info.Ctx, Value);
- return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal, Usage);
+ return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal, Usage,
+ CheckedTemps);
}
- if (Value.isMemberPointer())
+ if (Value.isMemberPointer() &&
+ CERK == CheckEvaluationResultKind::ConstantExpression)
return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value, Usage);
// Everything else is fine.
return true;
}
+/// 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,
+ Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen) {
+ CheckedTemporaries CheckedTemps;
+ return CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
+ Info, DiagLoc, Type, Value, Usage,
+ SourceLocation(), CheckedTemps);
+}
+
+/// Check that this evaluated value is fully-initialized and can be loaded by
+/// an lvalue-to-rvalue conversion.
+static bool CheckFullyInitialized(EvalInfo &Info, SourceLocation DiagLoc,
+ QualType Type, const APValue &Value) {
+ CheckedTemporaries CheckedTemps;
+ return CheckEvaluationResult(
+ CheckEvaluationResultKind::FullyInitialized, Info, DiagLoc, Type, Value,
+ Expr::EvaluateForCodeGen, SourceLocation(), CheckedTemps);
+}
+
+/// Enforce C++2a [expr.const]/4.17, which disallows new-expressions unless
+/// "the allocated storage is deallocated within the evaluation".
+static bool CheckMemoryLeaks(EvalInfo &Info) {
+ if (!Info.HeapAllocs.empty()) {
+ // We can still fold to a constant despite a compile-time memory leak,
+ // so long as the heap allocation isn't referenced in the result (we check
+ // that in CheckConstantExpression).
+ Info.CCEDiag(Info.HeapAllocs.begin()->second.AllocExpr,
+ diag::note_constexpr_memory_leak)
+ << unsigned(Info.HeapAllocs.size() - 1);
+ }
+ return true;
+}
+
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.
@@ -2323,7 +2470,7 @@ static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false);
Result = Value.trunc(LHS.getBitWidth());
if (Result.extend(BitWidth) != Value) {
- if (Info.checkingForOverflow())
+ if (Info.checkingForUndefinedBehavior())
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
diag::warn_integer_constant_overflow)
<< Result.toString(10) << E->getType();
@@ -2813,9 +2960,10 @@ static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
// FIXME: This is inefficient; we should probably introduce something similar
// to the LLVM ConstantDataArray to make this cheaper.
static void expandStringLiteral(EvalInfo &Info, const StringLiteral *S,
- APValue &Result) {
- const ConstantArrayType *CAT =
- Info.Ctx.getAsConstantArrayType(S->getType());
+ APValue &Result,
+ QualType AllocType = QualType()) {
+ const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(
+ AllocType.isNull() ? S->getType() : AllocType);
assert(CAT && "string literal isn't an array");
QualType CharType = CAT->getElementType();
assert(CharType->isIntegerType() && "unexpected character type");
@@ -2879,8 +3027,8 @@ static bool isReadByLvalueToRvalueConversion(QualType T) {
/// Diagnose an attempt to read from any unreadable field within the specified
/// type, which might be a class type.
-static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E,
- QualType T) {
+static bool diagnoseMutableFields(EvalInfo &Info, const Expr *E, AccessKinds AK,
+ QualType T) {
CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
if (!RD)
return false;
@@ -2895,17 +3043,17 @@ static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E,
// FIXME: Add core issue number for the union case.
if (Field->isMutable() &&
(RD->isUnion() || isReadByLvalueToRvalueConversion(Field->getType()))) {
- Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1) << Field;
+ Info.FFDiag(E, diag::note_constexpr_access_mutable, 1) << AK << Field;
Info.Note(Field->getLocation(), diag::note_declared_at);
return true;
}
- if (diagnoseUnreadableFields(Info, E, Field->getType()))
+ if (diagnoseMutableFields(Info, E, AK, Field->getType()))
return true;
}
for (auto &BaseSpec : RD->bases())
- if (diagnoseUnreadableFields(Info, E, BaseSpec.getType()))
+ if (diagnoseMutableFields(Info, E, AK, BaseSpec.getType()))
return true;
// All mutable fields were empty, and thus not actually read.
@@ -2913,7 +3061,8 @@ static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E,
}
static bool lifetimeStartedInEvaluation(EvalInfo &Info,
- APValue::LValueBase Base) {
+ APValue::LValueBase Base,
+ bool MutableSubobject = false) {
// A temporary we created.
if (Base.getCallIndex())
return true;
@@ -2922,19 +3071,42 @@ static bool lifetimeStartedInEvaluation(EvalInfo &Info,
if (!Evaluating)
return false;
- // The variable whose initializer we're evaluating.
- if (auto *BaseD = Base.dyn_cast<const ValueDecl*>())
- if (declaresSameEntity(Evaluating, BaseD))
- return true;
+ auto *BaseD = Base.dyn_cast<const ValueDecl*>();
- // A temporary lifetime-extended by the variable whose initializer we're
- // evaluating.
- if (auto *BaseE = Base.dyn_cast<const Expr *>())
- if (auto *BaseMTE = dyn_cast<MaterializeTemporaryExpr>(BaseE))
- if (declaresSameEntity(BaseMTE->getExtendingDecl(), Evaluating))
- return true;
+ switch (Info.IsEvaluatingDecl) {
+ case EvalInfo::EvaluatingDeclKind::None:
+ return false;
- return false;
+ case EvalInfo::EvaluatingDeclKind::Ctor:
+ // The variable whose initializer we're evaluating.
+ if (BaseD)
+ return declaresSameEntity(Evaluating, BaseD);
+
+ // A temporary lifetime-extended by the variable whose initializer we're
+ // evaluating.
+ if (auto *BaseE = Base.dyn_cast<const Expr *>())
+ if (auto *BaseMTE = dyn_cast<MaterializeTemporaryExpr>(BaseE))
+ return declaresSameEntity(BaseMTE->getExtendingDecl(), Evaluating);
+ return false;
+
+ case EvalInfo::EvaluatingDeclKind::Dtor:
+ // C++2a [expr.const]p6:
+ // [during constant destruction] the lifetime of a and its non-mutable
+ // subobjects (but not its mutable subobjects) [are] considered to start
+ // within e.
+ //
+ // FIXME: We can meaningfully extend this to cover non-const objects, but
+ // we will need special handling: we should be able to access only
+ // subobjects of such objects that are themselves declared const.
+ if (!BaseD ||
+ !(BaseD->getType().isConstQualified() ||
+ BaseD->getType()->isReferenceType()) ||
+ MutableSubobject)
+ return false;
+ return declaresSameEntity(Evaluating, BaseD);
+ }
+
+ llvm_unreachable("unknown evaluating decl kind");
}
namespace {
@@ -2952,13 +3124,13 @@ struct CompleteObject {
CompleteObject(APValue::LValueBase Base, APValue *Value, QualType Type)
: Base(Base), Value(Value), Type(Type) {}
- bool mayReadMutableMembers(EvalInfo &Info) const {
+ bool mayAccessMutableMembers(EvalInfo &Info, AccessKinds AK) const {
// In C++14 onwards, it is permitted to read a mutable member whose
// lifetime began within the evaluation.
// FIXME: Should we also allow this in C++11?
if (!Info.getLangOpts().CPlusPlus14)
return false;
- return lifetimeStartedInEvaluation(Info, Base);
+ return lifetimeStartedInEvaluation(Info, Base, /*MutableSubobject*/true);
}
explicit operator bool() const { return !Type.isNull(); }
@@ -3006,19 +3178,22 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
// Walk the designator's path to find the subobject.
for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
// Reading an indeterminate value is undefined, but assigning over one is OK.
- if (O->isAbsent() || (O->isIndeterminate() && handler.AccessKind != AK_Assign)) {
+ if ((O->isAbsent() && !(handler.AccessKind == AK_Construct && I == N)) ||
+ (O->isIndeterminate() && handler.AccessKind != AK_Construct &&
+ handler.AccessKind != AK_Assign &&
+ handler.AccessKind != AK_ReadObjectRepresentation)) {
if (!Info.checkingPotentialConstantExpression())
Info.FFDiag(E, diag::note_constexpr_access_uninit)
<< handler.AccessKind << O->isIndeterminate();
return handler.failed();
}
- // C++ [class.ctor]p5:
+ // C++ [class.ctor]p5, C++ [class.dtor]p5:
// const and volatile semantics are not applied on an object under
- // construction.
+ // {con,de}struction.
if ((ObjType.isConstQualified() || ObjType.isVolatileQualified()) &&
ObjType->isRecordType() &&
- Info.isEvaluatingConstructor(
+ Info.isEvaluatingCtorDtor(
Obj.Base, llvm::makeArrayRef(Sub.Entries.begin(),
Sub.Entries.begin() + I)) !=
ConstructionPhase::None) {
@@ -3061,9 +3236,9 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
// things we need to check: if there are any mutable subobjects, we
// cannot perform this read. (This only happens when performing a trivial
// copy or assignment.)
- if (ObjType->isRecordType() && handler.AccessKind == AK_Read &&
- !Obj.mayReadMutableMembers(Info) &&
- diagnoseUnreadableFields(Info, E, ObjType))
+ if (ObjType->isRecordType() &&
+ !Obj.mayAccessMutableMembers(Info, handler.AccessKind) &&
+ diagnoseMutableFields(Info, E, handler.AccessKind, ObjType))
return handler.failed();
}
@@ -3101,7 +3276,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if (O->getArrayInitializedElts() > Index)
O = &O->getArrayInitializedElt(Index);
- else if (handler.AccessKind != AK_Read) {
+ else if (!isRead(handler.AccessKind)) {
expandArray(*O, Index);
O = &O->getArrayInitializedElt(Index);
} else
@@ -3131,10 +3306,10 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
: O->getComplexFloatReal(), ObjType);
}
} else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) {
- if (Field->isMutable() && handler.AccessKind == AK_Read &&
- !Obj.mayReadMutableMembers(Info)) {
- Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1)
- << Field;
+ if (Field->isMutable() &&
+ !Obj.mayAccessMutableMembers(Info, handler.AccessKind)) {
+ Info.FFDiag(E, diag::note_constexpr_access_mutable, 1)
+ << handler.AccessKind << Field;
Info.Note(Field->getLocation(), diag::note_declared_at);
return handler.failed();
}
@@ -3145,9 +3320,18 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
const FieldDecl *UnionField = O->getUnionField();
if (!UnionField ||
UnionField->getCanonicalDecl() != Field->getCanonicalDecl()) {
- Info.FFDiag(E, diag::note_constexpr_access_inactive_union_member)
- << handler.AccessKind << Field << !UnionField << UnionField;
- return handler.failed();
+ if (I == N - 1 && handler.AccessKind == AK_Construct) {
+ // Placement new onto an inactive union member makes it active.
+ O->setUnion(Field, APValue());
+ } else {
+ // FIXME: If O->getUnionValue() is absent, report that there's no
+ // active union member rather than reporting the prior active union
+ // member. We'll need to fix nullptr_t to not use APValue() as its
+ // representation first.
+ Info.FFDiag(E, diag::note_constexpr_access_inactive_union_member)
+ << handler.AccessKind << Field << !UnionField << UnionField;
+ return handler.failed();
+ }
}
O = &O->getUnionValue();
} else
@@ -3171,15 +3355,17 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
namespace {
struct ExtractSubobjectHandler {
EvalInfo &Info;
+ const Expr *E;
APValue &Result;
-
- static const AccessKinds AccessKind = AK_Read;
+ const AccessKinds AccessKind;
typedef bool result_type;
bool failed() { return false; }
bool found(APValue &Subobj, QualType SubobjType) {
Result = Subobj;
- return true;
+ if (AccessKind == AK_ReadObjectRepresentation)
+ return true;
+ return CheckFullyInitialized(Info, E->getExprLoc(), SubobjType, Result);
}
bool found(APSInt &Value, QualType SubobjType) {
Result = APValue(Value);
@@ -3192,14 +3378,13 @@ struct ExtractSubobjectHandler {
};
} // end anonymous namespace
-const AccessKinds ExtractSubobjectHandler::AccessKind;
-
/// Extract the designated sub-object of an rvalue.
static bool extractSubobject(EvalInfo &Info, const Expr *E,
const CompleteObject &Obj,
- const SubobjectDesignator &Sub,
- APValue &Result) {
- ExtractSubobjectHandler Handler = { Info, Result };
+ const SubobjectDesignator &Sub, APValue &Result,
+ AccessKinds AK = AK_Read) {
+ assert(AK == AK_Read || AK == AK_ReadObjectRepresentation);
+ ExtractSubobjectHandler Handler = {Info, E, Result, AK};
return findSubobject(Info, E, Obj, Sub, Handler);
}
@@ -3345,13 +3530,13 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
}
}
- bool IsAccess = isFormalAccess(AK);
+ bool IsAccess = isAnyAccess(AK);
// 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 (IsAccess && LValType.isVolatileQualified()) {
+ if (isFormalAccess(AK) && LValType.isVolatileQualified()) {
if (Info.getLangOpts().CPlusPlus)
Info.FFDiag(E, diag::note_constexpr_access_volatile_type)
<< AK << LValType;
@@ -3386,8 +3571,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
// the variable we're reading must be const.
if (!Frame) {
if (Info.getLangOpts().CPlusPlus14 &&
- declaresSameEntity(
- VD, Info.EvaluatingDecl.dyn_cast<const ValueDecl *>())) {
+ lifetimeStartedInEvaluation(Info, LVal.Base)) {
// OK, we can read and modify an object if we're in the process of
// evaluating its initializer, because its lifetime began in this
// evaluation.
@@ -3446,6 +3630,14 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal, &LVal))
return CompleteObject();
+ } else if (DynamicAllocLValue DA = LVal.Base.dyn_cast<DynamicAllocLValue>()) {
+ Optional<DynAlloc*> Alloc = Info.lookupDynamicAlloc(DA);
+ if (!Alloc) {
+ Info.FFDiag(E, diag::note_constexpr_access_deleted_object) << AK;
+ return CompleteObject();
+ }
+ return CompleteObject(LVal.Base, &(*Alloc)->Value,
+ LVal.Base.getDynamicAllocType());
} else {
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
@@ -3469,11 +3661,14 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
// int x = ++r;
// constexpr int k = r;
// Therefore we use the C++14 rules in C++11 too.
- const ValueDecl *VD = Info.EvaluatingDecl.dyn_cast<const ValueDecl*>();
- const ValueDecl *ED = MTE->getExtendingDecl();
+ //
+ // Note that temporaries whose lifetimes began while evaluating a
+ // variable's constructor are not usable while evaluating the
+ // corresponding destructor, not even if they're of const-qualified
+ // types.
if (!(BaseType.isConstQualified() &&
BaseType->isIntegralOrEnumerationType()) &&
- !(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) {
+ !lifetimeStartedInEvaluation(Info, LVal.Base)) {
if (!IsAccess)
return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
Info.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
@@ -3525,15 +3720,22 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
/// case of a non-class 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) {
+/// \param WantObjectRepresentation - If true, we're looking for the object
+/// representation rather than the value, and in particular,
+/// there is no requirement that the result be fully initialized.
+static bool
+handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, QualType Type,
+ const LValue &LVal, APValue &RVal,
+ bool WantObjectRepresentation = false) {
if (LVal.Designator.Invalid)
return false;
// Check for special cases where there is no existing APValue to look at.
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
+ AccessKinds AK =
+ WantObjectRepresentation ? AK_ReadObjectRepresentation : AK_Read;
+
if (Base && !LVal.getLValueCallIndex() && !Type.isVolatileQualified()) {
if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) {
// In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the
@@ -3547,7 +3749,7 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
if (!Evaluate(Lit, Info, CLE->getInitializer()))
return false;
CompleteObject LitObj(LVal.Base, &Lit, Base->getType());
- return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal);
+ return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal, AK);
} else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) {
// Special-case character extraction so we don't have to construct an
// APValue for the whole string.
@@ -3562,7 +3764,7 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
}
if (LVal.Designator.isOnePastTheEnd()) {
if (Info.getLangOpts().CPlusPlus11)
- Info.FFDiag(Conv, diag::note_constexpr_access_past_end) << AK_Read;
+ Info.FFDiag(Conv, diag::note_constexpr_access_past_end) << AK;
else
Info.FFDiag(Conv);
return false;
@@ -3573,8 +3775,8 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
}
}
- CompleteObject Obj = findCompleteObject(Info, Conv, AK_Read, LVal, Type);
- return Obj && extractSubobject(Info, Conv, Obj, LVal.Designator, RVal);
+ CompleteObject Obj = findCompleteObject(Info, Conv, AK, LVal, Type);
+ return Obj && extractSubobject(Info, Conv, Obj, LVal.Designator, RVal, AK);
}
/// Perform an assignment of Val to LVal. Takes ownership of Val.
@@ -3866,7 +4068,7 @@ static bool handleIncDec(EvalInfo &Info, const Expr *E, const LValue &LVal,
/// 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())
+ if (Object->getType()->isPointerType() && Object->isRValue())
return EvaluatePointer(Object, This, Info);
if (Object->isGLValue())
@@ -4028,6 +4230,40 @@ static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
return CastToDerivedClass(Info, E, Result, TargetType, NewEntriesSize);
}
+/// Get the value to use for a default-initialized object of type T.
+static APValue getDefaultInitValue(QualType T) {
+ if (auto *RD = T->getAsCXXRecordDecl()) {
+ if (RD->isUnion())
+ return APValue((const FieldDecl*)nullptr);
+
+ APValue Struct(APValue::UninitStruct(), RD->getNumBases(),
+ std::distance(RD->field_begin(), RD->field_end()));
+
+ unsigned Index = 0;
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ End = RD->bases_end(); I != End; ++I, ++Index)
+ Struct.getStructBase(Index) = getDefaultInitValue(I->getType());
+
+ for (const auto *I : RD->fields()) {
+ if (I->isUnnamedBitfield())
+ continue;
+ Struct.getStructField(I->getFieldIndex()) =
+ getDefaultInitValue(I->getType());
+ }
+ return Struct;
+ }
+
+ if (auto *AT =
+ dyn_cast_or_null<ConstantArrayType>(T->getAsArrayTypeUnsafe())) {
+ APValue Array(APValue::UninitArray(), 0, AT->getSize().getZExtValue());
+ if (Array.hasArrayFiller())
+ Array.getArrayFiller() = getDefaultInitValue(AT->getElementType());
+ return Array;
+ }
+
+ return APValue::IndeterminateValue();
+}
+
namespace {
enum EvalStmtResult {
/// Evaluation failed.
@@ -4051,14 +4287,13 @@ static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
return true;
LValue Result;
- APValue &Val = createTemporary(VD, true, Result, *Info.CurrentCall);
+ APValue &Val =
+ Info.CurrentCall->createTemporary(VD, VD->getType(), true, Result);
const Expr *InitE = VD->getInit();
if (!InitE) {
- Info.FFDiag(VD->getBeginLoc(), diag::note_constexpr_uninitialized)
- << false << VD->getType();
- Val = APValue();
- return false;
+ Val = getDefaultInitValue(VD->getType());
+ return true;
}
if (InitE->isValueDependent())
@@ -4095,7 +4330,9 @@ static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl,
FullExpressionRAII Scope(Info);
if (CondDecl && !EvaluateDecl(Info, CondDecl))
return false;
- return EvaluateAsBooleanCondition(Cond, Result, Info);
+ if (!EvaluateAsBooleanCondition(Cond, Result, Info))
+ return false;
+ return Scope.destroy();
}
namespace {
@@ -4131,7 +4368,12 @@ static EvalStmtResult EvaluateLoopBody(StmtResult &Result, EvalInfo &Info,
const Stmt *Body,
const SwitchCase *Case = nullptr) {
BlockScopeRAII Scope(Info);
- switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body, Case)) {
+
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, Body, Case);
+ if (ESR != ESR_Failed && ESR != ESR_CaseNotFound && !Scope.destroy())
+ ESR = ESR_Failed;
+
+ switch (ESR) {
case ESR_Break:
return ESR_Succeeded;
case ESR_Succeeded:
@@ -4153,17 +4395,23 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
// Evaluate the switch condition.
APSInt Value;
{
- FullExpressionRAII Scope(Info);
if (const Stmt *Init = SS->getInit()) {
EvalStmtResult ESR = EvaluateStmt(Result, Info, Init);
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ ESR = ESR_Failed;
return ESR;
+ }
}
+
+ FullExpressionRAII CondScope(Info);
if (SS->getConditionVariable() &&
!EvaluateDecl(Info, SS->getConditionVariable()))
return ESR_Failed;
if (!EvaluateInteger(SS->getCond(), Value, Info))
return ESR_Failed;
+ if (!CondScope.destroy())
+ return ESR_Failed;
}
// Find the switch case corresponding to the value of the condition.
@@ -4187,10 +4435,14 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
}
if (!Found)
- return ESR_Succeeded;
+ return Scope.destroy() ? ESR_Succeeded : ESR_Failed;
// Search the switch body for the switch case and evaluate it from there.
- switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(), Found)) {
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(), Found);
+ if (ESR != ESR_Failed && ESR != ESR_CaseNotFound && !Scope.destroy())
+ return ESR_Failed;
+
+ switch (ESR) {
case ESR_Break:
return ESR_Succeeded;
case ESR_Succeeded:
@@ -4217,10 +4469,6 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// If we're hunting down a 'case' or 'default' label, recurse through
// substatements until we hit the label.
if (Case) {
- // FIXME: We don't start the lifetime of objects whose initialization we
- // jump over. However, such objects must be of class type with a trivial
- // default constructor that initialize all subobjects, so must be empty,
- // so this almost never matters.
switch (S->getStmtClass()) {
case Stmt::CompoundStmtClass:
// FIXME: Precompute which substatement of a compound statement we
@@ -4246,10 +4494,35 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// preceded by our switch label.
BlockScopeRAII Scope(Info);
+ // Step into the init statement in case it brings an (uninitialized)
+ // variable into scope.
+ if (const Stmt *Init = IS->getInit()) {
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, Init, Case);
+ if (ESR != ESR_CaseNotFound) {
+ assert(ESR != ESR_Succeeded);
+ return ESR;
+ }
+ }
+
+ // Condition variable must be initialized if it exists.
+ // FIXME: We can skip evaluating the body if there's a condition
+ // variable, as there can't be any case labels within it.
+ // (The same is true for 'for' statements.)
+
EvalStmtResult ESR = EvaluateStmt(Result, Info, IS->getThen(), Case);
- if (ESR != ESR_CaseNotFound || !IS->getElse())
+ if (ESR == ESR_Failed)
return ESR;
- return EvaluateStmt(Result, Info, IS->getElse(), Case);
+ if (ESR != ESR_CaseNotFound)
+ return Scope.destroy() ? ESR : ESR_Failed;
+ if (!IS->getElse())
+ return ESR_CaseNotFound;
+
+ ESR = EvaluateStmt(Result, Info, IS->getElse(), Case);
+ if (ESR == ESR_Failed)
+ return ESR;
+ if (ESR != ESR_CaseNotFound)
+ return Scope.destroy() ? ESR : ESR_Failed;
+ return ESR_CaseNotFound;
}
case Stmt::WhileStmtClass: {
@@ -4262,21 +4535,47 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
case Stmt::ForStmtClass: {
const ForStmt *FS = cast<ForStmt>(S);
+ BlockScopeRAII Scope(Info);
+
+ // Step into the init statement in case it brings an (uninitialized)
+ // variable into scope.
+ if (const Stmt *Init = FS->getInit()) {
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, Init, Case);
+ if (ESR != ESR_CaseNotFound) {
+ assert(ESR != ESR_Succeeded);
+ return ESR;
+ }
+ }
+
EvalStmtResult ESR =
EvaluateLoopBody(Result, Info, FS->getBody(), Case);
if (ESR != ESR_Continue)
return ESR;
if (FS->getInc()) {
FullExpressionRAII IncScope(Info);
- if (!EvaluateIgnoredValue(Info, FS->getInc()))
+ if (!EvaluateIgnoredValue(Info, FS->getInc()) || !IncScope.destroy())
return ESR_Failed;
}
break;
}
- case Stmt::DeclStmtClass:
- // FIXME: If the variable has initialization that can't be jumped over,
- // bail out of any immediately-surrounding compound-statement too.
+ case Stmt::DeclStmtClass: {
+ // Start the lifetime of any uninitialized variables we encounter. They
+ // might be used by the selected branch of the switch.
+ const DeclStmt *DS = cast<DeclStmt>(S);
+ for (const auto *D : DS->decls()) {
+ if (const auto *VD = dyn_cast<VarDecl>(D)) {
+ if (VD->hasLocalStorage() && !VD->getInit())
+ if (!EvaluateVarDecl(Info, VD))
+ return ESR_Failed;
+ // FIXME: If the variable has initialization that can't be jumped
+ // over, bail out of any immediately-surrounding compound-statement
+ // too. There can't be any case labels here.
+ }
+ }
+ return ESR_CaseNotFound;
+ }
+
default:
return ESR_CaseNotFound;
}
@@ -4287,8 +4586,10 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
if (const Expr *E = dyn_cast<Expr>(S)) {
// Don't bother evaluating beyond an expression-statement which couldn't
// be evaluated.
+ // FIXME: Do we need the FullExpressionRAII object here?
+ // VisitExprWithCleanups should create one when necessary.
FullExpressionRAII Scope(Info);
- if (!EvaluateIgnoredValue(Info, E))
+ if (!EvaluateIgnoredValue(Info, E) || !Scope.destroy())
return ESR_Failed;
return ESR_Succeeded;
}
@@ -4301,12 +4602,12 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
case Stmt::DeclStmtClass: {
const DeclStmt *DS = cast<DeclStmt>(S);
- for (const auto *DclIt : DS->decls()) {
+ for (const auto *D : DS->decls()) {
// Each declaration initialization is its own full-expression.
- // FIXME: This isn't quite right; if we're performing aggregate
- // initialization, each braced subexpression is its own full-expression.
FullExpressionRAII Scope(Info);
- if (!EvaluateDecl(Info, DclIt) && !Info.noteFailure())
+ if (!EvaluateDecl(Info, D) && !Info.noteFailure())
+ return ESR_Failed;
+ if (!Scope.destroy())
return ESR_Failed;
}
return ESR_Succeeded;
@@ -4320,7 +4621,7 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
? EvaluateInPlace(Result.Value, Info, *Result.Slot, RetExpr)
: Evaluate(Result.Value, Info, RetExpr)))
return ESR_Failed;
- return ESR_Returned;
+ return Scope.destroy() ? ESR_Returned : ESR_Failed;
}
case Stmt::CompoundStmtClass: {
@@ -4331,10 +4632,15 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
EvalStmtResult ESR = EvaluateStmt(Result, Info, BI, Case);
if (ESR == ESR_Succeeded)
Case = nullptr;
- else if (ESR != ESR_CaseNotFound)
+ else if (ESR != ESR_CaseNotFound) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
}
- return Case ? ESR_CaseNotFound : ESR_Succeeded;
+ if (Case)
+ return ESR_CaseNotFound;
+ return Scope.destroy() ? ESR_Succeeded : ESR_Failed;
}
case Stmt::IfStmtClass: {
@@ -4344,8 +4650,11 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
BlockScopeRAII Scope(Info);
if (const Stmt *Init = IS->getInit()) {
EvalStmtResult ESR = EvaluateStmt(Result, Info, Init);
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
}
bool Cond;
if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond))
@@ -4353,10 +4662,13 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
if (const Stmt *SubStmt = Cond ? IS->getThen() : IS->getElse()) {
EvalStmtResult ESR = EvaluateStmt(Result, Info, SubStmt);
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
}
- return ESR_Succeeded;
+ return Scope.destroy() ? ESR_Succeeded : ESR_Failed;
}
case Stmt::WhileStmtClass: {
@@ -4371,8 +4683,13 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
break;
EvalStmtResult ESR = EvaluateLoopBody(Result, Info, WS->getBody());
- if (ESR != ESR_Continue)
+ if (ESR != ESR_Continue) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
+ if (!Scope.destroy())
+ return ESR_Failed;
}
return ESR_Succeeded;
}
@@ -4387,7 +4704,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
Case = nullptr;
FullExpressionRAII CondScope(Info);
- if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info))
+ if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info) ||
+ !CondScope.destroy())
return ESR_Failed;
} while (Continue);
return ESR_Succeeded;
@@ -4395,14 +4713,17 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
case Stmt::ForStmtClass: {
const ForStmt *FS = cast<ForStmt>(S);
- BlockScopeRAII Scope(Info);
+ BlockScopeRAII ForScope(Info);
if (FS->getInit()) {
EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getInit());
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !ForScope.destroy())
+ return ESR_Failed;
return ESR;
+ }
}
while (true) {
- BlockScopeRAII Scope(Info);
+ BlockScopeRAII IterScope(Info);
bool Continue = true;
if (FS->getCond() && !EvaluateCond(Info, FS->getConditionVariable(),
FS->getCond(), Continue))
@@ -4411,16 +4732,22 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
break;
EvalStmtResult ESR = EvaluateLoopBody(Result, Info, FS->getBody());
- if (ESR != ESR_Continue)
+ if (ESR != ESR_Continue) {
+ if (ESR != ESR_Failed && (!IterScope.destroy() || !ForScope.destroy()))
+ return ESR_Failed;
return ESR;
+ }
if (FS->getInc()) {
FullExpressionRAII IncScope(Info);
- if (!EvaluateIgnoredValue(Info, FS->getInc()))
+ if (!EvaluateIgnoredValue(Info, FS->getInc()) || !IncScope.destroy())
return ESR_Failed;
}
+
+ if (!IterScope.destroy())
+ return ESR_Failed;
}
- return ESR_Succeeded;
+ return ForScope.destroy() ? ESR_Succeeded : ESR_Failed;
}
case Stmt::CXXForRangeStmtClass: {
@@ -4430,22 +4757,34 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// Evaluate the init-statement if present.
if (FS->getInit()) {
EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getInit());
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
}
// Initialize the __range variable.
EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getRangeStmt());
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
// Create the __begin and __end iterators.
ESR = EvaluateStmt(Result, Info, FS->getBeginStmt());
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
ESR = EvaluateStmt(Result, Info, FS->getEndStmt());
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && !Scope.destroy())
+ return ESR_Failed;
return ESR;
+ }
while (true) {
// Condition: __begin != __end.
@@ -4461,20 +4800,29 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// User's variable declaration, initialized by *__begin.
BlockScopeRAII InnerScope(Info);
ESR = EvaluateStmt(Result, Info, FS->getLoopVarStmt());
- if (ESR != ESR_Succeeded)
+ if (ESR != ESR_Succeeded) {
+ if (ESR != ESR_Failed && (!InnerScope.destroy() || !Scope.destroy()))
+ return ESR_Failed;
return ESR;
+ }
// Loop body.
ESR = EvaluateLoopBody(Result, Info, FS->getBody());
- if (ESR != ESR_Continue)
+ if (ESR != ESR_Continue) {
+ if (ESR != ESR_Failed && (!InnerScope.destroy() || !Scope.destroy()))
+ return ESR_Failed;
return ESR;
+ }
// Increment: ++__begin
if (!EvaluateIgnoredValue(Info, FS->getInc()))
return ESR_Failed;
+
+ if (!InnerScope.destroy())
+ return ESR_Failed;
}
- return ESR_Succeeded;
+ return Scope.destroy() ? ESR_Succeeded : ESR_Failed;
}
case Stmt::SwitchStmtClass:
@@ -4649,9 +4997,13 @@ static bool checkDynamicType(EvalInfo &Info, const Expr *E, const LValue &This,
/// Check that the pointee of the 'this' pointer in a member function call is
/// either within its lifetime or in its period of construction or destruction.
-static bool checkNonVirtualMemberCallThisPointer(EvalInfo &Info, const Expr *E,
- const LValue &This) {
- return checkDynamicType(Info, E, This, AK_MemberCall, false);
+static bool
+checkNonVirtualMemberCallThisPointer(EvalInfo &Info, const Expr *E,
+ const LValue &This,
+ const CXXMethodDecl *NamedMember) {
+ return checkDynamicType(
+ Info, E, This,
+ isa<CXXDestructorDecl>(NamedMember) ? AK_Destroy : AK_MemberCall, false);
}
struct DynamicType {
@@ -4699,16 +5051,19 @@ static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, const Expr *E,
ArrayRef<APValue::LValuePathEntry> Path = This.Designator.Entries;
for (unsigned PathLength = This.Designator.MostDerivedPathLength;
PathLength <= Path.size(); ++PathLength) {
- switch (Info.isEvaluatingConstructor(This.getLValueBase(),
- Path.slice(0, PathLength))) {
+ switch (Info.isEvaluatingCtorDtor(This.getLValueBase(),
+ Path.slice(0, PathLength))) {
case ConstructionPhase::Bases:
- // We're constructing a base class. This is not the dynamic type.
+ case ConstructionPhase::DestroyingBases:
+ // We're constructing or destroying a base class. This is not the dynamic
+ // type.
break;
case ConstructionPhase::None:
case ConstructionPhase::AfterBases:
- // We've finished constructing the base classes, so this is the dynamic
- // type.
+ case ConstructionPhase::Destroying:
+ // We've finished constructing the base classes and not yet started
+ // destroying them again, so this is the dynamic type.
return DynamicType{getBaseClassType(This.Designator, PathLength),
PathLength};
}
@@ -4725,8 +5080,9 @@ static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, const Expr *E,
static const CXXMethodDecl *HandleVirtualDispatch(
EvalInfo &Info, const Expr *E, LValue &This, const CXXMethodDecl *Found,
llvm::SmallVectorImpl<QualType> &CovariantAdjustmentPath) {
- Optional<DynamicType> DynType =
- ComputeDynamicType(Info, E, This, AK_MemberCall);
+ Optional<DynamicType> DynType = ComputeDynamicType(
+ Info, E, This,
+ isa<CXXDestructorDecl>(Found) ? AK_Destroy : AK_MemberCall);
if (!DynType)
return nullptr;
@@ -4862,8 +5218,7 @@ static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E,
if (!E->isGLValue()) {
// The value of a failed cast to pointer type is the null pointer value
// of the required result type.
- auto TargetVal = Info.Ctx.getTargetNullPointerValue(E->getType());
- Ptr.setNull(E->getType(), TargetVal);
+ Ptr.setNull(Info.Ctx, E->getType());
return true;
}
@@ -4928,39 +5283,6 @@ struct StartLifetimeOfUnionMemberHandler {
static const AccessKinds AccessKind = AK_Assign;
- APValue getDefaultInitValue(QualType SubobjType) {
- if (auto *RD = SubobjType->getAsCXXRecordDecl()) {
- if (RD->isUnion())
- return APValue((const FieldDecl*)nullptr);
-
- APValue Struct(APValue::UninitStruct(), RD->getNumBases(),
- std::distance(RD->field_begin(), RD->field_end()));
-
- unsigned Index = 0;
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- End = RD->bases_end(); I != End; ++I, ++Index)
- Struct.getStructBase(Index) = getDefaultInitValue(I->getType());
-
- for (const auto *I : RD->fields()) {
- if (I->isUnnamedBitfield())
- continue;
- Struct.getStructField(I->getFieldIndex()) =
- getDefaultInitValue(I->getType());
- }
- return Struct;
- }
-
- if (auto *AT = dyn_cast_or_null<ConstantArrayType>(
- SubobjType->getAsArrayTypeUnsafe())) {
- APValue Array(APValue::UninitArray(), 0, AT->getSize().getZExtValue());
- if (Array.hasArrayFiller())
- Array.getArrayFiller() = getDefaultInitValue(AT->getElementType());
- return Array;
- }
-
- return APValue::IndeterminateValue();
- }
-
typedef bool result_type;
bool failed() { return false; }
bool found(APValue &Subobj, QualType SubobjType) {
@@ -4973,7 +5295,8 @@ struct StartLifetimeOfUnionMemberHandler {
// * No variant members' lifetimes begin
// * All scalar subobjects whose lifetimes begin have indeterminate values
assert(SubobjType->isUnionType());
- if (!declaresSameEntity(Subobj.getUnionField(), Field))
+ if (!declaresSameEntity(Subobj.getUnionField(), Field) ||
+ !Subobj.getUnionValue().hasValue())
Subobj.setUnion(Field, getDefaultInitValue(Field->getType()));
return true;
}
@@ -5005,7 +5328,9 @@ static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *LHSExpr,
// -- If E is of the form A.B, S(E) contains the elements of S(A)...
if (auto *ME = dyn_cast<MemberExpr>(E)) {
auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
- if (!FD)
+ // Note that we can't implicitly start the lifetime of a reference,
+ // so we don't need to proceed any further if we reach one.
+ if (!FD || FD->getType()->isReferenceType())
break;
// ... and also contains A.B if B names a union member
@@ -5116,18 +5441,18 @@ static bool EvaluateArgs(ArrayRef<const Expr *> Args, ArgVector &ArgValues,
}
}
}
- for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
- I != E; ++I) {
- if (!Evaluate(ArgValues[I - Args.begin()], Info, *I)) {
+ for (unsigned Idx = 0; Idx < Args.size(); Idx++) {
+ if (!Evaluate(ArgValues[Idx], Info, Args[Idx])) {
// If we're checking for a potential constant expression, evaluate all
// initializers even if some of them fail.
if (!Info.noteFailure())
return false;
Success = false;
} else if (!ForbiddenNullArgs.empty() &&
- ForbiddenNullArgs[I - Args.begin()] &&
- ArgValues[I - Args.begin()].isNullPointer()) {
- Info.CCEDiag(*I, diag::note_non_null_attribute_failed);
+ ForbiddenNullArgs[Idx] &&
+ ArgValues[Idx].isLValue() &&
+ ArgValues[Idx].isNullPointer()) {
+ Info.CCEDiag(Args[Idx], diag::note_non_null_attribute_failed);
if (!Info.noteFailure())
return false;
Success = false;
@@ -5166,8 +5491,8 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
LValue RHS;
RHS.setFrom(Info.Ctx, ArgValues[0]);
APValue RHSValue;
- if (!handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
- RHS, RHSValue))
+ if (!handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), RHS,
+ RHSValue, MD->getParent()->isUnion()))
return false;
if (Info.getLangOpts().CPlusPlus2a && MD->isTrivial() &&
!HandleUnionActiveMemberChange(Info, Args[0], *This))
@@ -5230,7 +5555,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
CXXConstructorDecl::init_const_iterator I = Definition->init_begin();
{
FullExpressionRAII InitScope(Info);
- if (!EvaluateInPlace(Result, Info, This, (*I)->getInit()))
+ if (!EvaluateInPlace(Result, Info, This, (*I)->getInit()) ||
+ !InitScope.destroy())
return false;
}
return EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed;
@@ -5251,7 +5577,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
RHS.setFrom(Info.Ctx, ArgValues[0]);
return handleLValueToRValueConversion(
Info, E, Definition->getParamDecl(0)->getType().getNonReferenceType(),
- RHS, Result);
+ RHS, Result, Definition->getParent()->isUnion());
}
// Reserve space for the struct members.
@@ -5270,6 +5596,25 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
#ifndef NDEBUG
CXXRecordDecl::base_class_const_iterator BaseIt = RD->bases_begin();
#endif
+ CXXRecordDecl::field_iterator FieldIt = RD->field_begin();
+ auto SkipToField = [&](FieldDecl *FD, bool Indirect) {
+ // We might be initializing the same field again if this is an indirect
+ // field initialization.
+ if (FieldIt == RD->field_end() ||
+ FieldIt->getFieldIndex() > FD->getFieldIndex()) {
+ assert(Indirect && "fields out of order?");
+ return;
+ }
+
+ // Default-initialize any fields with no explicit initializer.
+ for (; !declaresSameEntity(*FieldIt, FD); ++FieldIt) {
+ assert(FieldIt != RD->field_end() && "missing field?");
+ if (!FieldIt->isUnnamedBitfield())
+ Result.getStructField(FieldIt->getFieldIndex()) =
+ getDefaultInitValue(FieldIt->getType());
+ }
+ ++FieldIt;
+ };
for (const auto *I : Definition->inits()) {
LValue Subobject = This;
LValue SubobjectParent = This;
@@ -5298,6 +5643,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
Result = APValue(FD);
Value = &Result.getUnionValue();
} else {
+ SkipToField(FD, false);
Value = &Result.getStructField(FD->getFieldIndex());
}
} else if (IndirectFieldDecl *IFD = I->getIndirectMember()) {
@@ -5317,8 +5663,10 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
if (CD->isUnion())
*Value = APValue(FD);
else
- *Value = APValue(APValue::UninitStruct(), CD->getNumBases(),
- std::distance(CD->field_begin(), CD->field_end()));
+ // FIXME: This immediately starts the lifetime of all members of an
+ // anonymous struct. It would be preferable to strictly start member
+ // lifetime in initialization order.
+ *Value = getDefaultInitValue(Info.Ctx.getRecordType(CD));
}
// Store Subobject as its parent before updating it for the last element
// in the chain.
@@ -5328,8 +5676,11 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
return false;
if (CD->isUnion())
Value = &Value->getUnionValue();
- else
+ else {
+ if (C == IndirectFieldChain.front() && !RD->isUnion())
+ SkipToField(FD, true);
Value = &Value->getStructField(FD->getFieldIndex());
+ }
}
} else {
llvm_unreachable("unknown base initializer kind");
@@ -5358,8 +5709,18 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
EvalObj.finishedConstructingBases();
}
+ // Default-initialize any remaining fields.
+ if (!RD->isUnion()) {
+ for (; FieldIt != RD->field_end(); ++FieldIt) {
+ if (!FieldIt->isUnnamedBitfield())
+ Result.getStructField(FieldIt->getFieldIndex()) =
+ getDefaultInitValue(FieldIt->getType());
+ }
+ }
+
return Success &&
- EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed;
+ EvaluateStmt(Ret, Info, Definition->getBody()) != ESR_Failed &&
+ LifetimeExtendedScope.destroy();
}
static bool HandleConstructorCall(const Expr *E, const LValue &This,
@@ -5374,6 +5735,381 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
Info, Result);
}
+static bool HandleDestructionImpl(EvalInfo &Info, SourceLocation CallLoc,
+ const LValue &This, APValue &Value,
+ QualType T) {
+ // Objects can only be destroyed while they're within their lifetimes.
+ // FIXME: We have no representation for whether an object of type nullptr_t
+ // is in its lifetime; it usually doesn't matter. Perhaps we should model it
+ // as indeterminate instead?
+ if (Value.isAbsent() && !T->isNullPtrType()) {
+ APValue Printable;
+ This.moveInto(Printable);
+ Info.FFDiag(CallLoc, diag::note_constexpr_destroy_out_of_lifetime)
+ << Printable.getAsString(Info.Ctx, Info.Ctx.getLValueReferenceType(T));
+ return false;
+ }
+
+ // Invent an expression for location purposes.
+ // FIXME: We shouldn't need to do this.
+ OpaqueValueExpr LocE(CallLoc, Info.Ctx.IntTy, VK_RValue);
+
+ // For arrays, destroy elements right-to-left.
+ if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(T)) {
+ uint64_t Size = CAT->getSize().getZExtValue();
+ QualType ElemT = CAT->getElementType();
+
+ LValue ElemLV = This;
+ ElemLV.addArray(Info, &LocE, CAT);
+ if (!HandleLValueArrayAdjustment(Info, &LocE, ElemLV, ElemT, Size))
+ return false;
+
+ // Ensure that we have actual array elements available to destroy; the
+ // destructors might mutate the value, so we can't run them on the array
+ // filler.
+ if (Size && Size > Value.getArrayInitializedElts())
+ expandArray(Value, Value.getArraySize() - 1);
+
+ for (; Size != 0; --Size) {
+ APValue &Elem = Value.getArrayInitializedElt(Size - 1);
+ if (!HandleLValueArrayAdjustment(Info, &LocE, ElemLV, ElemT, -1) ||
+ !HandleDestructionImpl(Info, CallLoc, ElemLV, Elem, ElemT))
+ return false;
+ }
+
+ // End the lifetime of this array now.
+ Value = APValue();
+ return true;
+ }
+
+ const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
+ if (!RD) {
+ if (T.isDestructedType()) {
+ Info.FFDiag(CallLoc, diag::note_constexpr_unsupported_destruction) << T;
+ return false;
+ }
+
+ Value = APValue();
+ return true;
+ }
+
+ if (RD->getNumVBases()) {
+ Info.FFDiag(CallLoc, diag::note_constexpr_virtual_base) << RD;
+ return false;
+ }
+
+ const CXXDestructorDecl *DD = RD->getDestructor();
+ if (!DD && !RD->hasTrivialDestructor()) {
+ Info.FFDiag(CallLoc);
+ return false;
+ }
+
+ if (!DD || DD->isTrivial() ||
+ (RD->isAnonymousStructOrUnion() && RD->isUnion())) {
+ // A trivial destructor just ends the lifetime of the object. Check for
+ // this case before checking for a body, because we might not bother
+ // building a body for a trivial destructor. Note that it doesn't matter
+ // whether the destructor is constexpr in this case; all trivial
+ // destructors are constexpr.
+ //
+ // If an anonymous union would be destroyed, some enclosing destructor must
+ // have been explicitly defined, and the anonymous union destruction should
+ // have no effect.
+ Value = APValue();
+ return true;
+ }
+
+ if (!Info.CheckCallLimit(CallLoc))
+ return false;
+
+ const FunctionDecl *Definition = nullptr;
+ const Stmt *Body = DD->getBody(Definition);
+
+ if (!CheckConstexprFunction(Info, CallLoc, DD, Definition, Body))
+ return false;
+
+ CallStackFrame Frame(Info, CallLoc, Definition, &This, nullptr);
+
+ // We're now in the period of destruction of this object.
+ unsigned BasesLeft = RD->getNumBases();
+ EvalInfo::EvaluatingDestructorRAII EvalObj(
+ Info,
+ ObjectUnderConstruction{This.getLValueBase(), This.Designator.Entries});
+ if (!EvalObj.DidInsert) {
+ // C++2a [class.dtor]p19:
+ // the behavior is undefined if the destructor is invoked for an object
+ // whose lifetime has ended
+ // (Note that formally the lifetime ends when the period of destruction
+ // begins, even though certain uses of the object remain valid until the
+ // period of destruction ends.)
+ Info.FFDiag(CallLoc, diag::note_constexpr_double_destroy);
+ return false;
+ }
+
+ // FIXME: Creating an APValue just to hold a nonexistent return value is
+ // wasteful.
+ APValue RetVal;
+ StmtResult Ret = {RetVal, nullptr};
+ if (EvaluateStmt(Ret, Info, Definition->getBody()) == ESR_Failed)
+ return false;
+
+ // A union destructor does not implicitly destroy its members.
+ if (RD->isUnion())
+ return true;
+
+ const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
+
+ // We don't have a good way to iterate fields in reverse, so collect all the
+ // fields first and then walk them backwards.
+ SmallVector<FieldDecl*, 16> Fields(RD->field_begin(), RD->field_end());
+ for (const FieldDecl *FD : llvm::reverse(Fields)) {
+ if (FD->isUnnamedBitfield())
+ continue;
+
+ LValue Subobject = This;
+ if (!HandleLValueMember(Info, &LocE, Subobject, FD, &Layout))
+ return false;
+
+ APValue *SubobjectValue = &Value.getStructField(FD->getFieldIndex());
+ if (!HandleDestructionImpl(Info, CallLoc, Subobject, *SubobjectValue,
+ FD->getType()))
+ return false;
+ }
+
+ if (BasesLeft != 0)
+ EvalObj.startedDestroyingBases();
+
+ // Destroy base classes in reverse order.
+ for (const CXXBaseSpecifier &Base : llvm::reverse(RD->bases())) {
+ --BasesLeft;
+
+ QualType BaseType = Base.getType();
+ LValue Subobject = This;
+ if (!HandleLValueDirectBase(Info, &LocE, Subobject, RD,
+ BaseType->getAsCXXRecordDecl(), &Layout))
+ return false;
+
+ APValue *SubobjectValue = &Value.getStructBase(BasesLeft);
+ if (!HandleDestructionImpl(Info, CallLoc, Subobject, *SubobjectValue,
+ BaseType))
+ return false;
+ }
+ assert(BasesLeft == 0 && "NumBases was wrong?");
+
+ // The period of destruction ends now. The object is gone.
+ Value = APValue();
+ return true;
+}
+
+namespace {
+struct DestroyObjectHandler {
+ EvalInfo &Info;
+ const Expr *E;
+ const LValue &This;
+ const AccessKinds AccessKind;
+
+ typedef bool result_type;
+ bool failed() { return false; }
+ bool found(APValue &Subobj, QualType SubobjType) {
+ return HandleDestructionImpl(Info, E->getExprLoc(), This, Subobj,
+ SubobjType);
+ }
+ bool found(APSInt &Value, QualType SubobjType) {
+ Info.FFDiag(E, diag::note_constexpr_destroy_complex_elem);
+ return false;
+ }
+ bool found(APFloat &Value, QualType SubobjType) {
+ Info.FFDiag(E, diag::note_constexpr_destroy_complex_elem);
+ return false;
+ }
+};
+}
+
+/// Perform a destructor or pseudo-destructor call on the given object, which
+/// might in general not be a complete object.
+static bool HandleDestruction(EvalInfo &Info, const Expr *E,
+ const LValue &This, QualType ThisType) {
+ CompleteObject Obj = findCompleteObject(Info, E, AK_Destroy, This, ThisType);
+ DestroyObjectHandler Handler = {Info, E, This, AK_Destroy};
+ return Obj && findSubobject(Info, E, Obj, This.Designator, Handler);
+}
+
+/// Destroy and end the lifetime of the given complete object.
+static bool HandleDestruction(EvalInfo &Info, SourceLocation Loc,
+ APValue::LValueBase LVBase, APValue &Value,
+ QualType T) {
+ // If we've had an unmodeled side-effect, we can't rely on mutable state
+ // (such as the object we're about to destroy) being correct.
+ if (Info.EvalStatus.HasSideEffects)
+ return false;
+
+ LValue LV;
+ LV.set({LVBase});
+ return HandleDestructionImpl(Info, Loc, LV, Value, T);
+}
+
+/// Perform a call to 'perator new' or to `__builtin_operator_new'.
+static bool HandleOperatorNewCall(EvalInfo &Info, const CallExpr *E,
+ LValue &Result) {
+ if (Info.checkingPotentialConstantExpression() ||
+ Info.SpeculativeEvaluationDepth)
+ return false;
+
+ // This is permitted only within a call to std::allocator<T>::allocate.
+ auto Caller = Info.getStdAllocatorCaller("allocate");
+ if (!Caller) {
+ Info.FFDiag(E->getExprLoc(), Info.getLangOpts().CPlusPlus2a
+ ? diag::note_constexpr_new_untyped
+ : diag::note_constexpr_new);
+ return false;
+ }
+
+ QualType ElemType = Caller.ElemType;
+ if (ElemType->isIncompleteType() || ElemType->isFunctionType()) {
+ Info.FFDiag(E->getExprLoc(),
+ diag::note_constexpr_new_not_complete_object_type)
+ << (ElemType->isIncompleteType() ? 0 : 1) << ElemType;
+ return false;
+ }
+
+ APSInt ByteSize;
+ if (!EvaluateInteger(E->getArg(0), ByteSize, Info))
+ return false;
+ bool IsNothrow = false;
+ for (unsigned I = 1, N = E->getNumArgs(); I != N; ++I) {
+ EvaluateIgnoredValue(Info, E->getArg(I));
+ IsNothrow |= E->getType()->isNothrowT();
+ }
+
+ CharUnits ElemSize;
+ if (!HandleSizeof(Info, E->getExprLoc(), ElemType, ElemSize))
+ return false;
+ APInt Size, Remainder;
+ APInt ElemSizeAP(ByteSize.getBitWidth(), ElemSize.getQuantity());
+ APInt::udivrem(ByteSize, ElemSizeAP, Size, Remainder);
+ if (Remainder != 0) {
+ // This likely indicates a bug in the implementation of 'std::allocator'.
+ Info.FFDiag(E->getExprLoc(), diag::note_constexpr_operator_new_bad_size)
+ << ByteSize << APSInt(ElemSizeAP, true) << ElemType;
+ return false;
+ }
+
+ if (ByteSize.getActiveBits() > ConstantArrayType::getMaxSizeBits(Info.Ctx)) {
+ if (IsNothrow) {
+ Result.setNull(Info.Ctx, E->getType());
+ return true;
+ }
+
+ Info.FFDiag(E, diag::note_constexpr_new_too_large) << APSInt(Size, true);
+ return false;
+ }
+
+ QualType AllocType = Info.Ctx.getConstantArrayType(ElemType, Size, nullptr,
+ ArrayType::Normal, 0);
+ APValue *Val = Info.createHeapAlloc(E, AllocType, Result);
+ *Val = APValue(APValue::UninitArray(), 0, Size.getZExtValue());
+ Result.addArray(Info, E, cast<ConstantArrayType>(AllocType));
+ return true;
+}
+
+static bool hasVirtualDestructor(QualType T) {
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ if (CXXDestructorDecl *DD = RD->getDestructor())
+ return DD->isVirtual();
+ return false;
+}
+
+static const FunctionDecl *getVirtualOperatorDelete(QualType T) {
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ if (CXXDestructorDecl *DD = RD->getDestructor())
+ return DD->isVirtual() ? DD->getOperatorDelete() : nullptr;
+ return nullptr;
+}
+
+/// Check that the given object is a suitable pointer to a heap allocation that
+/// still exists and is of the right kind for the purpose of a deletion.
+///
+/// On success, returns the heap allocation to deallocate. On failure, produces
+/// a diagnostic and returns None.
+static Optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E,
+ const LValue &Pointer,
+ DynAlloc::Kind DeallocKind) {
+ auto PointerAsString = [&] {
+ return Pointer.toString(Info.Ctx, Info.Ctx.VoidPtrTy);
+ };
+
+ DynamicAllocLValue DA = Pointer.Base.dyn_cast<DynamicAllocLValue>();
+ if (!DA) {
+ Info.FFDiag(E, diag::note_constexpr_delete_not_heap_alloc)
+ << PointerAsString();
+ if (Pointer.Base)
+ NoteLValueLocation(Info, Pointer.Base);
+ return None;
+ }
+
+ Optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA);
+ if (!Alloc) {
+ Info.FFDiag(E, diag::note_constexpr_double_delete);
+ return None;
+ }
+
+ QualType AllocType = Pointer.Base.getDynamicAllocType();
+ if (DeallocKind != (*Alloc)->getKind()) {
+ Info.FFDiag(E, diag::note_constexpr_new_delete_mismatch)
+ << DeallocKind << (*Alloc)->getKind() << AllocType;
+ NoteLValueLocation(Info, Pointer.Base);
+ return None;
+ }
+
+ bool Subobject = false;
+ if (DeallocKind == DynAlloc::New) {
+ Subobject = Pointer.Designator.MostDerivedPathLength != 0 ||
+ Pointer.Designator.isOnePastTheEnd();
+ } else {
+ Subobject = Pointer.Designator.Entries.size() != 1 ||
+ Pointer.Designator.Entries[0].getAsArrayIndex() != 0;
+ }
+ if (Subobject) {
+ Info.FFDiag(E, diag::note_constexpr_delete_subobject)
+ << PointerAsString() << Pointer.Designator.isOnePastTheEnd();
+ return None;
+ }
+
+ return Alloc;
+}
+
+// Perform a call to 'operator delete' or '__builtin_operator_delete'.
+bool HandleOperatorDeleteCall(EvalInfo &Info, const CallExpr *E) {
+ if (Info.checkingPotentialConstantExpression() ||
+ Info.SpeculativeEvaluationDepth)
+ return false;
+
+ // This is permitted only within a call to std::allocator<T>::deallocate.
+ if (!Info.getStdAllocatorCaller("deallocate")) {
+ Info.FFDiag(E->getExprLoc());
+ return true;
+ }
+
+ LValue Pointer;
+ if (!EvaluatePointer(E->getArg(0), Pointer, Info))
+ return false;
+ for (unsigned I = 1, N = E->getNumArgs(); I != N; ++I)
+ EvaluateIgnoredValue(Info, E->getArg(I));
+
+ if (Pointer.Designator.Invalid)
+ return false;
+
+ // Deleting a null pointer has no effect.
+ if (Pointer.isNullPointer())
+ return true;
+
+ if (!CheckDeleteKind(Info, E, Pointer, DynAlloc::StdAllocator))
+ return false;
+
+ Info.HeapAllocs.erase(Pointer.Base.get<DynamicAllocLValue>());
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Generic Evaluation
//===----------------------------------------------------------------------===//
@@ -5706,9 +6442,8 @@ class BufferToAPValueConverter {
QualType RepresentationType = Ty->getDecl()->getIntegerType();
assert(!RepresentationType.isNull() &&
"enum forward decl should be caught by Sema");
- const BuiltinType *AsBuiltin =
- RepresentationType.getCanonicalType()->getAs<BuiltinType>();
- assert(AsBuiltin && "non-integral enum underlying type?");
+ const auto *AsBuiltin =
+ RepresentationType.getCanonicalType()->castAs<BuiltinType>();
// Recurse into the underlying type. Treat std::byte transparently as
// unsigned char.
return visit(AsBuiltin, Offset, /*EnumTy=*/Ty);
@@ -5752,7 +6487,7 @@ class BufferToAPValueConverter {
#define NON_CANONICAL_UNLESS_DEPENDENT(Class, Base) \
case Type::Class: \
llvm_unreachable("either dependent or not canonical!");
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
llvm_unreachable("Unhandled Type::TypeClass");
}
@@ -5843,9 +6578,9 @@ static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue,
LValue SourceLValue;
APValue SourceRValue;
SourceLValue.setFrom(Info.Ctx, SourceValue);
- if (!handleLValueToRValueConversion(Info, BCE,
- BCE->getSubExpr()->getType().withConst(),
- SourceLValue, SourceRValue))
+ if (!handleLValueToRValueConversion(
+ Info, BCE, BCE->getSubExpr()->getType().withConst(), SourceLValue,
+ SourceRValue, /*WantObjectRepresentation=*/true))
return false;
// Read out SourceValue into a char buffer.
@@ -5984,10 +6719,16 @@ public:
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.
- bool VisitExprWithCleanups(const ExprWithCleanups *E)
- { return StmtVisitorTy::Visit(E->getSubExpr()); }
+ bool VisitExprWithCleanups(const ExprWithCleanups *E) {
+ FullExpressionRAII Scope(Info);
+ return StmtVisitorTy::Visit(E->getSubExpr()) && Scope.destroy();
+ }
+
+ // Temporaries are registered when created, so we don't care about
+ // CXXBindTemporaryExpr.
+ bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E) {
+ return StmtVisitorTy::Visit(E->getSubExpr());
+ }
bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E) {
CCEDiag(E, diag::note_constexpr_invalid_cast) << 0;
@@ -6024,10 +6765,18 @@ public:
}
}
+ bool VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *E) {
+ return StmtVisitorTy::Visit(E->getSemanticForm());
+ }
+
bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) {
// Evaluate and cache the common expression. We treat it as a temporary,
// even though it's not quite the same thing.
- if (!Evaluate(Info.CurrentCall->createTemporary(E->getOpaqueValue(), false),
+ LValue CommonLV;
+ if (!Evaluate(Info.CurrentCall->createTemporary(
+ E->getOpaqueValue(),
+ getStorageType(Info.Ctx, E->getOpaqueValue()), false,
+ CommonLV),
Info, E->getCommon()))
return false;
@@ -6047,6 +6796,8 @@ public:
// Always assume __builtin_constant_p(...) ? ... : ... is a potential
// constant expression; we can't check whether it's potentially foldable.
+ // FIXME: We should instead treat __builtin_constant_p as non-constant if
+ // it would return 'false' in this mode.
if (Info.checkingPotentialConstantExpression() && IsBcpCall)
return false;
@@ -6104,11 +6855,21 @@ public:
HasQualifier = ME->hasQualifier();
} else if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(Callee)) {
// Indirect bound member calls ('.*' or '->*').
- Member = dyn_cast_or_null<CXXMethodDecl>(
- HandleMemberPointerAccess(Info, BE, ThisVal, false));
+ const ValueDecl *D =
+ HandleMemberPointerAccess(Info, BE, ThisVal, false);
+ if (!D)
+ return false;
+ Member = dyn_cast<CXXMethodDecl>(D);
if (!Member)
return Error(Callee);
This = &ThisVal;
+ } else if (const auto *PDE = dyn_cast<CXXPseudoDestructorExpr>(Callee)) {
+ if (!Info.getLangOpts().CPlusPlus2a)
+ Info.CCEDiag(PDE, diag::note_constexpr_pseudo_destructor);
+ // FIXME: If pseudo-destructor calls ever start ending the lifetime of
+ // their callee, we should start calling HandleDestruction here.
+ // For now, we just evaluate the object argument and discard it.
+ return EvaluateObjectArgument(Info, PDE->getBase(), ThisVal);
} else
return Error(Callee);
FD = Member;
@@ -6177,6 +6938,17 @@ public:
FD = cast<CXXMethodDecl>(CorrespondingCallOpSpecialization);
} else
FD = LambdaCallOp;
+ } else if (FD->isReplaceableGlobalAllocationFunction()) {
+ if (FD->getDeclName().getCXXOverloadedOperator() == OO_New ||
+ FD->getDeclName().getCXXOverloadedOperator() == OO_Array_New) {
+ LValue Ptr;
+ if (!HandleOperatorNewCall(Info, E, Ptr))
+ return false;
+ Ptr.moveInto(Result);
+ return true;
+ } else {
+ return HandleOperatorDeleteCall(Info, E);
+ }
}
} else
return Error(E);
@@ -6192,11 +6964,20 @@ public:
return false;
} else {
// Check that the 'this' pointer points to an object of the right type.
- if (!checkNonVirtualMemberCallThisPointer(Info, E, *This))
+ // FIXME: If this is an assignment operator call, we may need to change
+ // the active union member before we check this.
+ if (!checkNonVirtualMemberCallThisPointer(Info, E, *This, NamedMember))
return false;
}
}
+ // Destructor calls are different enough that they have their own codepath.
+ if (auto *DD = dyn_cast<CXXDestructorDecl>(FD)) {
+ assert(This && "no 'this' pointer for destructor call");
+ return HandleDestruction(Info, E, *This,
+ Info.Ctx.getRecordType(DD->getParent()));
+ }
+
const FunctionDecl *Definition = nullptr;
Stmt *Body = FD->getBody(Definition);
@@ -6329,14 +7110,14 @@ public:
bool VisitStmtExpr(const StmtExpr *E) {
// We will have checked the full-expressions inside the statement expression
// when they were completed, and don't need to check them again now.
- if (Info.checkingForOverflow())
+ if (Info.checkingForUndefinedBehavior())
return Error(E);
- BlockScopeRAII Scope(Info);
const CompoundStmt *CS = E->getSubStmt();
if (CS->body_empty())
return true;
+ BlockScopeRAII Scope(Info);
for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
BE = CS->body_end();
/**/; ++BI) {
@@ -6347,7 +7128,7 @@ public:
diag::note_constexpr_stmt_expr_unsupported);
return false;
}
- return this->Visit(FinalExpr);
+ return this->Visit(FinalExpr) && Scope.destroy();
}
APValue ReturnValue;
@@ -6440,7 +7221,7 @@ public:
const ValueDecl *MD = E->getMemberDecl();
if (const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) {
- assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() ==
+ assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() ==
FD->getParent()->getCanonicalDecl() && "record / field mismatch");
(void)BaseTy;
if (!HandleLValueMember(this->Info, E, Result, FD))
@@ -6696,16 +7477,14 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
*Value = APValue();
Result.set(E);
} else {
- Value = &createTemporary(E, E->getStorageDuration() == SD_Automatic, Result,
- *Info.CurrentCall);
+ Value = &Info.CurrentCall->createTemporary(
+ E, E->getType(), E->getStorageDuration() == SD_Automatic, Result);
}
QualType Type = Inner->getType();
// Materialize the temporary itself.
- if (!EvaluateInPlace(*Value, Info, Result, Inner) ||
- (E->getStorageDuration() == SD_Static &&
- !CheckConstantExpression(Info, E->getExprLoc(), Type, *Value))) {
+ if (!EvaluateInPlace(*Value, Info, Result, Inner)) {
*Value = APValue();
return false;
}
@@ -7035,8 +7814,7 @@ public:
return true;
}
bool ZeroInitialization(const Expr *E) {
- auto TargetVal = Info.Ctx.getTargetNullPointerValue(E->getType());
- Result.setNull(E->getType(), TargetVal);
+ Result.setNull(Info.Ctx, E->getType());
return true;
}
@@ -7097,6 +7875,8 @@ public:
return true;
}
+ bool VisitCXXNewExpr(const CXXNewExpr *E);
+
bool VisitSourceLocExpr(const SourceLocExpr *E) {
assert(E->isStringType() && "SourceLocExpr isn't a pointer type?");
APValue LValResult = E->EvaluateInContext(
@@ -7161,12 +7941,22 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
// 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;
+ if (!Result.InvalidBase && !Result.Designator.Invalid &&
+ !Result.IsNullPtr &&
+ Info.Ctx.hasSameUnqualifiedType(Result.Designator.getType(Info.Ctx),
+ E->getType()->getPointeeType()) &&
+ Info.getStdAllocatorCaller("allocate")) {
+ // Inside a call to std::allocator::allocate and friends, we permit
+ // casting from void* back to cv1 T* for a pointer that points to a
+ // cv2 T.
+ } else {
+ 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;
+ }
}
if (E->getCastKind() == CK_AddressSpaceConversion && Result.IsNullPtr)
ZeroInitialization(E);
@@ -7229,8 +8019,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!evaluateLValue(SubExpr, Result))
return false;
} else {
- APValue &Value = createTemporary(SubExpr, false, Result,
- *Info.CurrentCall);
+ APValue &Value = Info.CurrentCall->createTemporary(
+ SubExpr, SubExpr->getType(), false, Result);
if (!EvaluateInPlace(Value, Info, Result, SubExpr))
return false;
}
@@ -7403,6 +8193,8 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return true;
}
+ case Builtin::BI__builtin_operator_new:
+ return HandleOperatorNewCall(Info, E, Result);
case Builtin::BI__builtin_launder:
return evaluatePointer(E->getArg(0), Result);
case Builtin::BIstrchr:
@@ -7638,6 +8430,8 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
while (true) {
APValue Val;
+ // FIXME: Set WantObjectRepresentation to true if we're copying a
+ // char-like type?
if (!handleLValueToRValueConversion(Info, E, T, Src, Val) ||
!handleAssignment(Info, E, Dest, T, Val))
return false;
@@ -7652,10 +8446,208 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
}
default:
- return visitNonBuiltinCallExpr(E);
+ break;
}
+
+ return visitNonBuiltinCallExpr(E);
}
+static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This,
+ APValue &Result, const InitListExpr *ILE,
+ QualType AllocType);
+
+bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
+ if (!Info.getLangOpts().CPlusPlus2a)
+ Info.CCEDiag(E, diag::note_constexpr_new);
+
+ // We cannot speculatively evaluate a delete expression.
+ if (Info.SpeculativeEvaluationDepth)
+ return false;
+
+ FunctionDecl *OperatorNew = E->getOperatorNew();
+
+ bool IsNothrow = false;
+ bool IsPlacement = false;
+ if (OperatorNew->isReservedGlobalPlacementOperator() &&
+ Info.CurrentCall->isStdFunction() && !E->isArray()) {
+ // FIXME Support array placement new.
+ assert(E->getNumPlacementArgs() == 1);
+ if (!EvaluatePointer(E->getPlacementArg(0), Result, Info))
+ return false;
+ if (Result.Designator.Invalid)
+ return false;
+ IsPlacement = true;
+ } else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) {
+ Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
+ << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
+ return false;
+ } else if (E->getNumPlacementArgs()) {
+ // The only new-placement list we support is of the form (std::nothrow).
+ //
+ // FIXME: There is no restriction on this, but it's not clear that any
+ // other form makes any sense. We get here for cases such as:
+ //
+ // new (std::align_val_t{N}) X(int)
+ //
+ // (which should presumably be valid only if N is a multiple of
+ // alignof(int), and in any case can't be deallocated unless N is
+ // alignof(X) and X has new-extended alignment).
+ if (E->getNumPlacementArgs() != 1 ||
+ !E->getPlacementArg(0)->getType()->isNothrowT())
+ return Error(E, diag::note_constexpr_new_placement);
+
+ LValue Nothrow;
+ if (!EvaluateLValue(E->getPlacementArg(0), Nothrow, Info))
+ return false;
+ IsNothrow = true;
+ }
+
+ const Expr *Init = E->getInitializer();
+ const InitListExpr *ResizedArrayILE = nullptr;
+
+ QualType AllocType = E->getAllocatedType();
+ if (Optional<const Expr*> ArraySize = E->getArraySize()) {
+ const Expr *Stripped = *ArraySize;
+ for (; auto *ICE = dyn_cast<ImplicitCastExpr>(Stripped);
+ Stripped = ICE->getSubExpr())
+ if (ICE->getCastKind() != CK_NoOp &&
+ ICE->getCastKind() != CK_IntegralCast)
+ break;
+
+ llvm::APSInt ArrayBound;
+ if (!EvaluateInteger(Stripped, ArrayBound, Info))
+ return false;
+
+ // C++ [expr.new]p9:
+ // The expression is erroneous if:
+ // -- [...] its value before converting to size_t [or] applying the
+ // second standard conversion sequence is less than zero
+ if (ArrayBound.isSigned() && ArrayBound.isNegative()) {
+ if (IsNothrow)
+ return ZeroInitialization(E);
+
+ Info.FFDiag(*ArraySize, diag::note_constexpr_new_negative)
+ << ArrayBound << (*ArraySize)->getSourceRange();
+ return false;
+ }
+
+ // -- its value is such that the size of the allocated object would
+ // exceed the implementation-defined limit
+ if (ConstantArrayType::getNumAddressingBits(Info.Ctx, AllocType,
+ ArrayBound) >
+ ConstantArrayType::getMaxSizeBits(Info.Ctx)) {
+ if (IsNothrow)
+ return ZeroInitialization(E);
+
+ Info.FFDiag(*ArraySize, diag::note_constexpr_new_too_large)
+ << ArrayBound << (*ArraySize)->getSourceRange();
+ return false;
+ }
+
+ // -- the new-initializer is a braced-init-list and the number of
+ // array elements for which initializers are provided [...]
+ // exceeds the number of elements to initialize
+ if (Init) {
+ auto *CAT = Info.Ctx.getAsConstantArrayType(Init->getType());
+ assert(CAT && "unexpected type for array initializer");
+
+ unsigned Bits =
+ std::max(CAT->getSize().getBitWidth(), ArrayBound.getBitWidth());
+ llvm::APInt InitBound = CAT->getSize().zextOrSelf(Bits);
+ llvm::APInt AllocBound = ArrayBound.zextOrSelf(Bits);
+ if (InitBound.ugt(AllocBound)) {
+ if (IsNothrow)
+ return ZeroInitialization(E);
+
+ Info.FFDiag(*ArraySize, diag::note_constexpr_new_too_small)
+ << AllocBound.toString(10, /*Signed=*/false)
+ << InitBound.toString(10, /*Signed=*/false)
+ << (*ArraySize)->getSourceRange();
+ return false;
+ }
+
+ // If the sizes differ, we must have an initializer list, and we need
+ // special handling for this case when we initialize.
+ if (InitBound != AllocBound)
+ ResizedArrayILE = cast<InitListExpr>(Init);
+ }
+
+ AllocType = Info.Ctx.getConstantArrayType(AllocType, ArrayBound, nullptr,
+ ArrayType::Normal, 0);
+ } else {
+ assert(!AllocType->isArrayType() &&
+ "array allocation with non-array new");
+ }
+
+ APValue *Val;
+ if (IsPlacement) {
+ AccessKinds AK = AK_Construct;
+ struct FindObjectHandler {
+ EvalInfo &Info;
+ const Expr *E;
+ QualType AllocType;
+ const AccessKinds AccessKind;
+ APValue *Value;
+
+ typedef bool result_type;
+ bool failed() { return false; }
+ bool found(APValue &Subobj, QualType SubobjType) {
+ // FIXME: Reject the cases where [basic.life]p8 would not permit the
+ // old name of the object to be used to name the new object.
+ if (!Info.Ctx.hasSameUnqualifiedType(SubobjType, AllocType)) {
+ Info.FFDiag(E, diag::note_constexpr_placement_new_wrong_type) <<
+ SubobjType << AllocType;
+ return false;
+ }
+ Value = &Subobj;
+ return true;
+ }
+ bool found(APSInt &Value, QualType SubobjType) {
+ Info.FFDiag(E, diag::note_constexpr_construct_complex_elem);
+ return false;
+ }
+ bool found(APFloat &Value, QualType SubobjType) {
+ Info.FFDiag(E, diag::note_constexpr_construct_complex_elem);
+ return false;
+ }
+ } Handler = {Info, E, AllocType, AK, nullptr};
+
+ CompleteObject Obj = findCompleteObject(Info, E, AK, Result, AllocType);
+ if (!Obj || !findSubobject(Info, E, Obj, Result.Designator, Handler))
+ return false;
+
+ Val = Handler.Value;
+
+ // [basic.life]p1:
+ // The lifetime of an object o of type T ends when [...] the storage
+ // which the object occupies is [...] reused by an object that is not
+ // nested within o (6.6.2).
+ *Val = APValue();
+ } else {
+ // Perform the allocation and obtain a pointer to the resulting object.
+ Val = Info.createHeapAlloc(E, AllocType, Result);
+ if (!Val)
+ return false;
+ }
+
+ if (ResizedArrayILE) {
+ if (!EvaluateArrayNewInitList(Info, Result, *Val, ResizedArrayILE,
+ AllocType))
+ return false;
+ } else if (Init) {
+ if (!EvaluateInPlace(*Val, Info, Result, Init))
+ return false;
+ } else {
+ *Val = getDefaultInitValue(AllocType);
+ }
+
+ // Array new returns a pointer to the first element, not a pointer to the
+ // array.
+ if (auto *AT = AllocType->getAsArrayTypeUnsafe())
+ Result.addArray(Info, E, cast<ConstantArrayType>(AT));
+
+ return true;
+}
//===----------------------------------------------------------------------===//
// Member Pointer Evaluation
//===----------------------------------------------------------------------===//
@@ -7779,7 +8771,6 @@ namespace {
bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
-
bool VisitBinCmp(const BinaryOperator *E);
};
}
@@ -8013,15 +9004,11 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
if (Result.hasValue())
return true;
- // We can get here in two different ways:
- // 1) We're performing value-initialization, and should zero-initialize
- // the object, or
- // 2) We're performing default-initialization of an object with a trivial
- // constexpr default constructor, in which case we should start the
- // lifetimes of all the base subobjects (there can be no data member
- // subobjects in this case) per [basic.life]p1.
- // Either way, ZeroInitialization is appropriate.
- return ZeroInitialization(E, T);
+ if (ZeroInit)
+ return ZeroInitialization(E, T);
+
+ Result = getDefaultInitValue(T);
+ return true;
}
const FunctionDecl *Definition = nullptr;
@@ -8121,9 +9108,8 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr(
bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) {
const CXXRecordDecl *ClosureClass = E->getLambdaClass();
- if (ClosureClass->isInvalidDecl()) return false;
-
- if (Info.checkingPotentialConstantExpression()) return true;
+ if (ClosureClass->isInvalidDecl())
+ return false;
const size_t NumFields =
std::distance(ClosureClass->field_begin(), ClosureClass->field_end());
@@ -8183,7 +9169,8 @@ public:
/// Visit an expression which constructs the value of this temporary.
bool VisitConstructExpr(const Expr *E) {
- APValue &Value = createTemporary(E, false, Result, *Info.CurrentCall);
+ APValue &Value =
+ Info.CurrentCall->createTemporary(E, E->getType(), false, Result);
return EvaluateInPlace(Value, Info, Result, E);
}
@@ -8383,7 +9370,7 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
bool
VectorExprEvaluator::ZeroInitialization(const Expr *E) {
- const VectorType *VT = E->getType()->getAs<VectorType>();
+ const auto *VT = E->getType()->castAs<VectorType>();
QualType EltTy = VT->getElementType();
APValue ZeroElement;
if (EltTy->isIntegerType())
@@ -8441,14 +9428,16 @@ namespace {
bool VisitCallExpr(const CallExpr *E) {
return handleCallExpr(E, Result, &This);
}
- bool VisitInitListExpr(const InitListExpr *E);
+ bool VisitInitListExpr(const InitListExpr *E,
+ QualType AllocType = QualType());
bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
bool VisitCXXConstructExpr(const CXXConstructExpr *E);
bool VisitCXXConstructExpr(const CXXConstructExpr *E,
const LValue &Subobject,
APValue *Value, QualType Type);
- bool VisitStringLiteral(const StringLiteral *E) {
- expandStringLiteral(Info, E, Result);
+ bool VisitStringLiteral(const StringLiteral *E,
+ QualType AllocType = QualType()) {
+ expandStringLiteral(Info, E, Result, AllocType);
return true;
}
};
@@ -8460,6 +9449,15 @@ static bool EvaluateArray(const Expr *E, const LValue &This,
return ArrayExprEvaluator(Info, This, Result).Visit(E);
}
+static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This,
+ APValue &Result, const InitListExpr *ILE,
+ QualType AllocType) {
+ assert(ILE->isRValue() && ILE->getType()->isArrayType() &&
+ "not an array rvalue");
+ return ArrayExprEvaluator(Info, This, Result)
+ .VisitInitListExpr(ILE, AllocType);
+}
+
// Return true iff the given array filler may depend on the element index.
static bool MaybeElementDependentArrayFiller(const Expr *FillerExpr) {
// For now, just whitelist non-class value-initialization and initialization
@@ -8476,15 +9474,23 @@ static bool MaybeElementDependentArrayFiller(const Expr *FillerExpr) {
return true;
}
-bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
- const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(E->getType());
+bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E,
+ QualType AllocType) {
+ const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(
+ AllocType.isNull() ? E->getType() : AllocType);
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->isStringLiteralInit())
- return Visit(E->getInit(0));
+ if (E->isStringLiteralInit()) {
+ auto *SL = dyn_cast<StringLiteral>(E->getInit(0)->IgnoreParens());
+ // FIXME: Support ObjCEncodeExpr here once we support it in
+ // ArrayExprEvaluator generally.
+ if (!SL)
+ return Error(E);
+ return VisitStringLiteral(SL, AllocType);
+ }
bool Success = true;
@@ -8543,8 +9549,12 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
}
bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
+ LValue CommonLV;
if (E->getCommonExpr() &&
- !Evaluate(Info.CurrentCall->createTemporary(E->getCommonExpr(), false),
+ !Evaluate(Info.CurrentCall->createTemporary(
+ E->getCommonExpr(),
+ getStorageType(Info.Ctx, E->getCommonExpr()), false,
+ CommonLV),
Info, E->getCommonExpr()->getSourceExpr()))
return false;
@@ -8762,6 +9772,7 @@ public:
bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
bool VisitSourceLocExpr(const SourceLocExpr *E);
+ bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);
// FIXME: Missing: array subscript of vector, member of vector
};
@@ -8944,7 +9955,7 @@ EvaluateBuiltinClassifyType(QualType T, const LangOptions &LangOpts) {
#define DEPENDENT_TYPE(ID, BASE) case Type::ID:
#define NON_CANONICAL_TYPE(ID, BASE) case Type::ID:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(ID, BASE) case Type::ID:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
case Type::Auto:
case Type::DeducedTemplateSpecialization:
llvm_unreachable("unexpected non-canonical or dependent type");
@@ -9008,6 +10019,9 @@ EvaluateBuiltinClassifyType(QualType T, const LangOptions &LangOpts) {
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
case BuiltinType::OCLReserveID:
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
return GCCTypeClass::None;
case BuiltinType::Dependent:
@@ -9161,6 +10175,8 @@ static QualType getObjectType(APValue::LValueBase B) {
return E->getType();
} else if (B.is<TypeInfoLValue>()) {
return B.getTypeInfoType();
+ } else if (B.is<DynamicAllocLValue>()) {
+ return B.getDynamicAllocType();
}
return QualType();
@@ -9499,14 +10515,11 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
// size of the referenced object.
switch (Info.EvalMode) {
case EvalInfo::EM_ConstantExpression:
- case EvalInfo::EM_PotentialConstantExpression:
case EvalInfo::EM_ConstantFold:
- case EvalInfo::EM_EvaluateForOverflow:
case EvalInfo::EM_IgnoreSideEffects:
// Leave it to IR generation.
return Error(E);
case EvalInfo::EM_ConstantExpressionUnevaluated:
- case EvalInfo::EM_PotentialConstantExpressionUnevaluated:
// Reduce it to a constant now.
return Success((Type & 2) ? 0 : -1, E);
}
@@ -10834,7 +11847,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
Info.CCEDiag(E, diag::note_constexpr_pointer_subtraction_not_same_array);
QualType Type = E->getLHS()->getType();
- QualType ElementType = Type->getAs<PointerType>()->getPointeeType();
+ QualType ElementType = Type->castAs<PointerType>()->getPointeeType();
CharUnits ElementSize;
if (!HandleSizeof(Info, E->getExprLoc(), ElementType, ElementSize))
@@ -11242,6 +12255,12 @@ bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
return Success(E->getValue(), E);
}
+bool IntExprEvaluator::VisitConceptSpecializationExpr(
+ const ConceptSpecializationExpr *E) {
+ return Success(E->isSatisfied(), E);
+}
+
+
bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
switch (E->getOpcode()) {
default:
@@ -11731,9 +12750,9 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!Visit(E->getSubExpr()))
return false;
- QualType To = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType To = E->getType()->castAs<ComplexType>()->getElementType();
QualType From
- = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
+ = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
return HandleFloatToFloatCast(Info, E, From, To, Result.FloatReal) &&
HandleFloatToFloatCast(Info, E, From, To, Result.FloatImag);
@@ -11743,9 +12762,9 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!Visit(E->getSubExpr()))
return false;
- QualType To = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType To = E->getType()->castAs<ComplexType>()->getElementType();
QualType From
- = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
+ = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.makeComplexInt();
return HandleFloatToIntCast(Info, E, From, Result.FloatReal,
To, Result.IntReal) &&
@@ -11767,9 +12786,9 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!Visit(E->getSubExpr()))
return false;
- QualType To = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType To = E->getType()->castAs<ComplexType>()->getElementType();
QualType From
- = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
+ = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.IntReal = HandleIntToIntCast(Info, E, To, From, Result.IntReal);
Result.IntImag = HandleIntToIntCast(Info, E, To, From, Result.IntImag);
@@ -12143,17 +13162,98 @@ public:
bool VisitCallExpr(const CallExpr *E) {
switch (E->getBuiltinCallee()) {
- default:
- return ExprEvaluatorBaseTy::VisitCallExpr(E);
case Builtin::BI__assume:
case Builtin::BI__builtin_assume:
// The argument is not evaluated!
return true;
+
+ case Builtin::BI__builtin_operator_delete:
+ return HandleOperatorDeleteCall(Info, E);
+
+ default:
+ break;
}
+
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
}
+
+ bool VisitCXXDeleteExpr(const CXXDeleteExpr *E);
};
} // end anonymous namespace
+bool VoidExprEvaluator::VisitCXXDeleteExpr(const CXXDeleteExpr *E) {
+ // We cannot speculatively evaluate a delete expression.
+ if (Info.SpeculativeEvaluationDepth)
+ return false;
+
+ FunctionDecl *OperatorDelete = E->getOperatorDelete();
+ if (!OperatorDelete->isReplaceableGlobalAllocationFunction()) {
+ Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
+ << isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete;
+ return false;
+ }
+
+ const Expr *Arg = E->getArgument();
+
+ LValue Pointer;
+ if (!EvaluatePointer(Arg, Pointer, Info))
+ return false;
+ if (Pointer.Designator.Invalid)
+ return false;
+
+ // Deleting a null pointer has no effect.
+ if (Pointer.isNullPointer()) {
+ // This is the only case where we need to produce an extension warning:
+ // the only other way we can succeed is if we find a dynamic allocation,
+ // and we will have warned when we allocated it in that case.
+ if (!Info.getLangOpts().CPlusPlus2a)
+ Info.CCEDiag(E, diag::note_constexpr_new);
+ return true;
+ }
+
+ Optional<DynAlloc *> Alloc = CheckDeleteKind(
+ Info, E, Pointer, E->isArrayForm() ? DynAlloc::ArrayNew : DynAlloc::New);
+ if (!Alloc)
+ return false;
+ QualType AllocType = Pointer.Base.getDynamicAllocType();
+
+ // For the non-array case, the designator must be empty if the static type
+ // does not have a virtual destructor.
+ if (!E->isArrayForm() && Pointer.Designator.Entries.size() != 0 &&
+ !hasVirtualDestructor(Arg->getType()->getPointeeType())) {
+ Info.FFDiag(E, diag::note_constexpr_delete_base_nonvirt_dtor)
+ << Arg->getType()->getPointeeType() << AllocType;
+ return false;
+ }
+
+ // For a class type with a virtual destructor, the selected operator delete
+ // is the one looked up when building the destructor.
+ if (!E->isArrayForm() && !E->isGlobalDelete()) {
+ const FunctionDecl *VirtualDelete = getVirtualOperatorDelete(AllocType);
+ if (VirtualDelete &&
+ !VirtualDelete->isReplaceableGlobalAllocationFunction()) {
+ Info.FFDiag(E, diag::note_constexpr_new_non_replaceable)
+ << isa<CXXMethodDecl>(VirtualDelete) << VirtualDelete;
+ return false;
+ }
+ }
+
+ if (!HandleDestruction(Info, E->getExprLoc(), Pointer.getLValueBase(),
+ (*Alloc)->Value, AllocType))
+ return false;
+
+ if (!Info.HeapAllocs.erase(Pointer.Base.dyn_cast<DynamicAllocLValue>())) {
+ // The element was already erased. This means the destructor call also
+ // deleted the object.
+ // FIXME: This probably results in undefined behavior before we get this
+ // far, and should be diagnosed elsewhere first.
+ Info.FFDiag(E, diag::note_constexpr_double_delete);
+ return false;
+ }
+
+ return true;
+}
+
static bool EvaluateVoid(const Expr *E, EvalInfo &Info) {
assert(E->isRValue() && E->getType()->isVoidType());
return VoidExprEvaluator(Info).Visit(E);
@@ -12203,13 +13303,14 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
return true;
} else if (T->isArrayType()) {
LValue LV;
- APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall);
+ APValue &Value =
+ Info.CurrentCall->createTemporary(E, T, false, LV);
if (!EvaluateArray(E, LV, Value, Info))
return false;
Result = Value;
} else if (T->isRecordType()) {
LValue LV;
- APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall);
+ APValue &Value = Info.CurrentCall->createTemporary(E, T, false, LV);
if (!EvaluateRecord(E, LV, Value, Info))
return false;
Result = Value;
@@ -12223,7 +13324,7 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
QualType Unqual = T.getAtomicUnqualifiedType();
if (Unqual->isArrayType() || Unqual->isRecordType()) {
LValue LV;
- APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall);
+ APValue &Value = Info.CurrentCall->createTemporary(E, Unqual, false, LV);
if (!EvaluateAtomic(E, &LV, Value, Info))
return false;
} else {
@@ -12273,6 +13374,18 @@ static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
/// 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 (Info.EnableNewConstInterp) {
+ auto &InterpCtx = Info.Ctx.getInterpContext();
+ switch (InterpCtx.evaluateAsRValue(Info, E, Result)) {
+ case interp::InterpResult::Success:
+ return true;
+ case interp::InterpResult::Fail:
+ return false;
+ case interp::InterpResult::Bail:
+ break;
+ }
+ }
+
if (E->getType().isNull())
return false;
@@ -12290,7 +13403,8 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
}
// Check this core constant expression is a constant expression.
- return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result);
+ return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result) &&
+ CheckMemoryLeaks(Info);
}
static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result,
@@ -12439,10 +13553,12 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx,
EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold);
Info.InConstantContext = InConstantContext;
LValue LV;
- if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects ||
+ CheckedTemporaries CheckedTemps;
+ if (!EvaluateLValue(this, LV, Info) || !Info.discardCleanups() ||
+ Result.HasSideEffects ||
!CheckLValueConstantExpression(Info, getExprLoc(),
Ctx.getLValueReferenceType(getType()), LV,
- Expr::EvaluateForCodeGen))
+ Expr::EvaluateForCodeGen, CheckedTemps))
return false;
LV.moveInto(Result.Val);
@@ -12458,11 +13574,15 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, ConstExprUsage Usage,
EvalInfo Info(Ctx, Result, EM);
Info.InConstantContext = true;
- if (!::Evaluate(Result.Val, Info, this))
+ if (!::Evaluate(Result.Val, Info, this) || Result.HasSideEffects)
return false;
- return CheckConstantExpression(Info, getExprLoc(), getType(), Result.Val,
- Usage);
+ if (!Info.discardCleanups())
+ llvm_unreachable("Unhandled cleanup; missing full expression marker?");
+
+ return CheckConstantExpression(Info, getExprLoc(), getStorageType(Ctx, this),
+ Result.Val, Usage) &&
+ CheckMemoryLeaks(Info);
}
bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
@@ -12480,11 +13600,29 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
Expr::EvalStatus EStatus;
EStatus.Diag = &Notes;
- EvalInfo InitInfo(Ctx, EStatus, VD->isConstexpr()
+ EvalInfo Info(Ctx, EStatus, VD->isConstexpr()
? EvalInfo::EM_ConstantExpression
: EvalInfo::EM_ConstantFold);
- InitInfo.setEvaluatingDecl(VD, Value);
- InitInfo.InConstantContext = true;
+ Info.setEvaluatingDecl(VD, Value);
+ Info.InConstantContext = true;
+
+ SourceLocation DeclLoc = VD->getLocation();
+ QualType DeclTy = VD->getType();
+
+ if (Info.EnableNewConstInterp) {
+ auto &InterpCtx = const_cast<ASTContext &>(Ctx).getInterpContext();
+ switch (InterpCtx.evaluateAsInitializer(Info, VD, Value)) {
+ case interp::InterpResult::Fail:
+ // Bail out if an error was encountered.
+ return false;
+ case interp::InterpResult::Success:
+ // Evaluation succeeded and value was set.
+ return CheckConstantExpression(Info, DeclLoc, DeclTy, Value);
+ case interp::InterpResult::Bail:
+ // Evaluate the value again for the tree evaluator to use.
+ break;
+ }
+ }
LValue LVal;
LVal.set(VD);
@@ -12494,20 +13632,62 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
// 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,
+ !DeclTy->isReferenceType()) {
+ ImplicitValueInitExpr VIE(DeclTy);
+ if (!EvaluateInPlace(Value, Info, LVal, &VIE,
/*AllowNonLiteralTypes=*/true))
return false;
}
- if (!EvaluateInPlace(Value, InitInfo, LVal, this,
+ if (!EvaluateInPlace(Value, Info, LVal, this,
/*AllowNonLiteralTypes=*/true) ||
EStatus.HasSideEffects)
return false;
- return CheckConstantExpression(InitInfo, VD->getLocation(), VD->getType(),
- Value);
+ // At this point, any lifetime-extended temporaries are completely
+ // initialized.
+ Info.performLifetimeExtension();
+
+ if (!Info.discardCleanups())
+ llvm_unreachable("Unhandled cleanup; missing full expression marker?");
+
+ return CheckConstantExpression(Info, DeclLoc, DeclTy, Value) &&
+ CheckMemoryLeaks(Info);
+}
+
+bool VarDecl::evaluateDestruction(
+ SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+ assert(getEvaluatedValue() && !getEvaluatedValue()->isAbsent() &&
+ "cannot evaluate destruction of non-constant-initialized variable");
+
+ Expr::EvalStatus EStatus;
+ EStatus.Diag = &Notes;
+
+ // Make a copy of the value for the destructor to mutate.
+ APValue DestroyedValue = *getEvaluatedValue();
+
+ EvalInfo Info(getASTContext(), EStatus, EvalInfo::EM_ConstantExpression);
+ Info.setEvaluatingDecl(this, DestroyedValue,
+ EvalInfo::EvaluatingDeclKind::Dtor);
+ Info.InConstantContext = true;
+
+ SourceLocation DeclLoc = getLocation();
+ QualType DeclTy = getType();
+
+ LValue LVal;
+ LVal.set(this);
+
+ // FIXME: Consider storing whether this variable has constant destruction in
+ // the EvaluatedStmt so that CodeGen can query it.
+ if (!HandleDestruction(Info, DeclLoc, LVal.Base, DestroyedValue, DeclTy) ||
+ EStatus.HasSideEffects)
+ return false;
+
+ if (!Info.discardCleanups())
+ llvm_unreachable("Unhandled cleanup; missing full expression marker?");
+
+ ensureEvaluatedStmt()->HasConstantDestruction = true;
+ return true;
}
/// isEvaluatable - Call EvaluateAsRValue to see if this expression can be
@@ -12546,8 +13726,9 @@ APSInt Expr::EvaluateKnownConstIntCheckOverflow(
EvalResult EVResult;
EVResult.Diag = Diag;
- EvalInfo Info(Ctx, EVResult, EvalInfo::EM_EvaluateForOverflow);
+ EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
Info.InConstantContext = true;
+ Info.CheckingForUndefinedBehavior = true;
bool Result = ::EvaluateAsRValue(Info, this, EVResult.Val);
(void)Result;
@@ -12564,7 +13745,8 @@ void Expr::EvaluateForOverflow(const ASTContext &Ctx) const {
bool IsConst;
EvalResult EVResult;
if (!FastEvaluateAsRValue(this, EVResult, Ctx, IsConst)) {
- EvalInfo Info(Ctx, EVResult, EvalInfo::EM_EvaluateForOverflow);
+ EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
+ Info.CheckingForUndefinedBehavior = true;
(void)::EvaluateAsRValue(Info, this, EVResult.Val);
}
}
@@ -12752,6 +13934,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::CXXBoolLiteralExprClass:
case Expr::CXXScalarValueInitExprClass:
case Expr::TypeTraitExprClass:
+ case Expr::ConceptSpecializationExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
case Expr::CXXNoexceptExprClass:
@@ -12766,6 +13949,9 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
return CheckEvalInICE(E, Ctx);
return ICEDiag(IK_NotICE, E->getBeginLoc());
}
+ case Expr::CXXRewrittenBinaryOperatorClass:
+ return CheckICE(cast<CXXRewrittenBinaryOperator>(E)->getSemanticForm(),
+ Ctx);
case Expr::DeclRefExprClass: {
if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
return NoDiag();
@@ -13111,7 +14297,11 @@ bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression);
APValue Scratch;
- bool IsConstExpr = ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch);
+ bool IsConstExpr =
+ ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch) &&
+ // FIXME: We don't produce a diagnostic for this, but the callers that
+ // call us on arbitrary full-expressions should generally not care.
+ Info.discardCleanups() && !Status.HasSideEffects;
if (!Diags.empty()) {
IsConstExpr = false;
@@ -13163,7 +14353,8 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
// Build fake call to Callee.
CallStackFrame Frame(Info, Callee->getLocation(), Callee, ThisPtr,
ArgValues.data());
- return Evaluate(Value, Info, this) && !Info.EvalStatus.HasSideEffects;
+ return Evaluate(Value, Info, this) && Info.discardCleanups() &&
+ !Info.EvalStatus.HasSideEffects;
}
bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
@@ -13178,9 +14369,21 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
Expr::EvalStatus Status;
Status.Diag = &Diags;
- EvalInfo Info(FD->getASTContext(), Status,
- EvalInfo::EM_PotentialConstantExpression);
+ EvalInfo Info(FD->getASTContext(), Status, EvalInfo::EM_ConstantExpression);
Info.InConstantContext = true;
+ Info.CheckingPotentialConstantExpression = true;
+
+ // The constexpr VM attempts to compile all methods to bytecode here.
+ if (Info.EnableNewConstInterp) {
+ auto &InterpCtx = Info.Ctx.getInterpContext();
+ switch (InterpCtx.isPotentialConstantExpr(Info, FD)) {
+ case interp::InterpResult::Success:
+ case interp::InterpResult::Fail:
+ return Diags.empty();
+ case interp::InterpResult::Bail:
+ break;
+ }
+ }
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
const CXXRecordDecl *RD = MD ? MD->getParent()->getCanonicalDecl() : nullptr;
@@ -13219,8 +14422,9 @@ bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
Status.Diag = &Diags;
EvalInfo Info(FD->getASTContext(), Status,
- EvalInfo::EM_PotentialConstantExpressionUnevaluated);
+ EvalInfo::EM_ConstantExpressionUnevaluated);
Info.InConstantContext = true;
+ Info.CheckingPotentialConstantExpression = true;
// Fabricate a call stack frame to give the arguments a plausible cover story.
ArrayRef<const Expr*> Args;
diff --git a/lib/AST/ExternalASTMerger.cpp b/lib/AST/ExternalASTMerger.cpp
index 61e657da7c91..f678c2dd3b59 100644
--- a/lib/AST/ExternalASTMerger.cpp
+++ b/lib/AST/ExternalASTMerger.cpp
@@ -101,21 +101,103 @@ private:
ExternalASTMerger &Parent;
ASTImporter Reverse;
const ExternalASTMerger::OriginMap &FromOrigins;
-
+ /// @see ExternalASTMerger::ImporterSource::Temporary
+ bool TemporarySource;
+ /// Map of imported declarations back to the declarations they originated
+ /// from.
+ llvm::DenseMap<Decl *, Decl *> ToOrigin;
+ /// @see ExternalASTMerger::ImporterSource::Merger
+ ExternalASTMerger *SourceMerger;
llvm::raw_ostream &logs() { return Parent.logs(); }
public:
LazyASTImporter(ExternalASTMerger &_Parent, ASTContext &ToContext,
- FileManager &ToFileManager, ASTContext &FromContext,
- FileManager &FromFileManager,
- const ExternalASTMerger::OriginMap &_FromOrigins)
- : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager,
- /*MinimalImport=*/true),
- Parent(_Parent), Reverse(FromContext, FromFileManager, ToContext,
- ToFileManager, /*MinimalImport=*/true), FromOrigins(_FromOrigins) {}
+ FileManager &ToFileManager,
+ const ExternalASTMerger::ImporterSource &S,
+ std::shared_ptr<ASTImporterSharedState> SharedState)
+ : ASTImporter(ToContext, ToFileManager, S.getASTContext(),
+ S.getFileManager(),
+ /*MinimalImport=*/true, SharedState),
+ Parent(_Parent),
+ Reverse(S.getASTContext(), S.getFileManager(), ToContext, ToFileManager,
+ /*MinimalImport=*/true),
+ FromOrigins(S.getOriginMap()), TemporarySource(S.isTemporary()),
+ SourceMerger(S.getMerger()) {}
+
+ llvm::Expected<Decl *> ImportImpl(Decl *FromD) override {
+ if (!TemporarySource || !SourceMerger)
+ return ASTImporter::ImportImpl(FromD);
+
+ // If we get here, then this source is importing from a temporary ASTContext
+ // that also has another ExternalASTMerger attached. It could be
+ // possible that the current ExternalASTMerger and the temporary ASTContext
+ // share a common ImporterSource, which means that the temporary
+ // AST could contain declarations that were imported from a source
+ // that this ExternalASTMerger can access directly. Instead of importing
+ // such declarations from the temporary ASTContext, they should instead
+ // be directly imported by this ExternalASTMerger from the original
+ // source. This way the ExternalASTMerger can safely do a minimal import
+ // without creating incomplete declarations originated from a temporary
+ // ASTContext. If we would try to complete such declarations later on, we
+ // would fail to do so as their temporary AST could be deleted (which means
+ // that the missing parts of the minimally imported declaration in that
+ // ASTContext were also deleted).
+ //
+ // The following code tracks back any declaration that needs to be
+ // imported from the temporary ASTContext to a persistent ASTContext.
+ // Then the ExternalASTMerger tries to import from the persistent
+ // ASTContext directly by using the associated ASTImporter. If that
+ // succeeds, this ASTImporter just maps the declarations imported by
+ // the other (persistent) ASTImporter to this (temporary) ASTImporter.
+ // The steps can be visualized like this:
+ //
+ // Target AST <--- 3. Indirect import --- Persistent AST
+ // ^ of persistent decl ^
+ // | |
+ // 1. Current import 2. Tracking back to persistent decl
+ // 4. Map persistent decl |
+ // & pretend we imported. |
+ // | |
+ // Temporary AST -------------------------------'
+
+ // First, ask the ExternalASTMerger of the source where the temporary
+ // declaration originated from.
+ Decl *Persistent = SourceMerger->FindOriginalDecl(FromD);
+ // FromD isn't from a persistent AST, so just do a normal import.
+ if (!Persistent)
+ return ASTImporter::ImportImpl(FromD);
+ // Now ask the current ExternalASTMerger to try import the persistent
+ // declaration into the target.
+ ASTContext &PersistentCtx = Persistent->getASTContext();
+ ASTImporter &OtherImporter = Parent.ImporterForOrigin(PersistentCtx);
+ // Check that we never end up in the current Importer again.
+ assert((&PersistentCtx != &getFromContext()) && (&OtherImporter != this) &&
+ "Delegated to same Importer?");
+ auto DeclOrErr = OtherImporter.Import(Persistent);
+ // Errors when importing the persistent decl are treated as if we
+ // had errors with importing the temporary decl.
+ if (!DeclOrErr)
+ return DeclOrErr.takeError();
+ Decl *D = *DeclOrErr;
+ // Tell the current ASTImporter that this has already been imported
+ // to prevent any further queries for the temporary decl.
+ MapImported(FromD, D);
+ return D;
+ }
+
+ /// Implements the ASTImporter interface for tracking back a declaration
+ /// to its original declaration it came from.
+ Decl *GetOriginalDecl(Decl *To) override {
+ auto It = ToOrigin.find(To);
+ if (It != ToOrigin.end())
+ return It->second;
+ return nullptr;
+ }
/// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin
/// map is kept up to date. Also set the appropriate flags.
void Imported(Decl *From, Decl *To) override {
+ ToOrigin[To] = From;
+
if (auto *ToDC = dyn_cast<DeclContext>(To)) {
const bool LoggingEnabled = Parent.LoggingEnabled();
if (LoggingEnabled)
@@ -314,28 +396,40 @@ void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origi
ExternalASTMerger::ExternalASTMerger(const ImporterTarget &Target,
llvm::ArrayRef<ImporterSource> Sources) : LogStream(&llvm::nulls()), Target(Target) {
+ SharedState = std::make_shared<ASTImporterSharedState>(
+ *Target.AST.getTranslationUnitDecl());
AddSources(Sources);
}
+Decl *ExternalASTMerger::FindOriginalDecl(Decl *D) {
+ assert(&D->getASTContext() == &Target.AST);
+ for (const auto &I : Importers)
+ if (auto Result = I->GetOriginalDecl(D))
+ return Result;
+ return nullptr;
+}
+
void ExternalASTMerger::AddSources(llvm::ArrayRef<ImporterSource> Sources) {
for (const ImporterSource &S : Sources) {
- assert(&S.AST != &Target.AST);
- Importers.push_back(llvm::make_unique<LazyASTImporter>(
- *this, Target.AST, Target.FM, S.AST, S.FM, S.OM));
+ assert(&S.getASTContext() != &Target.AST);
+ // Check that the associated merger actually imports into the source AST.
+ assert(!S.getMerger() || &S.getMerger()->Target.AST == &S.getASTContext());
+ Importers.push_back(std::make_unique<LazyASTImporter>(
+ *this, Target.AST, Target.FM, S, SharedState));
}
}
void ExternalASTMerger::RemoveSources(llvm::ArrayRef<ImporterSource> Sources) {
if (LoggingEnabled())
for (const ImporterSource &S : Sources)
- logs() << "(ExternalASTMerger*)" << (void*)this
- << " removing source (ASTContext*)" << (void*)&S.AST
+ logs() << "(ExternalASTMerger*)" << (void *)this
+ << " removing source (ASTContext*)" << (void *)&S.getASTContext()
<< "\n";
Importers.erase(
std::remove_if(Importers.begin(), Importers.end(),
[&Sources](std::unique_ptr<ASTImporter> &Importer) -> bool {
for (const ImporterSource &S : Sources) {
- if (&Importer->getFromContext() == &S.AST)
+ if (&Importer->getFromContext() == &S.getASTContext())
return true;
}
return false;
@@ -345,7 +439,7 @@ void ExternalASTMerger::RemoveSources(llvm::ArrayRef<ImporterSource> Sources) {
std::pair<const DeclContext *, DCOrigin> Origin = *OI;
bool Erase = false;
for (const ImporterSource &S : Sources) {
- if (&S.AST == Origin.second.AST) {
+ if (&S.getASTContext() == Origin.second.AST) {
Erase = true;
break;
}
diff --git a/lib/AST/FormatString.cpp b/lib/AST/FormatString.cpp
index 578d5bc56733..fcc0b3b11e25 100644
--- a/lib/AST/FormatString.cpp
+++ b/lib/AST/FormatString.cpp
@@ -359,6 +359,7 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
case BuiltinType::SChar:
case BuiltinType::UChar:
case BuiltinType::Char_U:
+ case BuiltinType::Bool:
return Match;
}
return NoMatch;
@@ -386,6 +387,9 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
case BuiltinType::SChar:
case BuiltinType::Char_U:
case BuiltinType::UChar:
+ case BuiltinType::Bool:
+ if (T == C.UnsignedShortTy || T == C.ShortTy)
+ return NoMatchTypeConfusion;
return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match
: NoMatch;
case BuiltinType::Short:
diff --git a/lib/AST/FormatStringParsing.h b/lib/AST/FormatStringParsing.h
index 9da829adcb49..764e5d46394d 100644
--- a/lib/AST/FormatStringParsing.h
+++ b/lib/AST/FormatStringParsing.h
@@ -1,3 +1,16 @@
+//===----- FormatStringParsing.h - Format String Parsing --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides some shared functions between printf and scanf format string
+// parsing code.
+//
+//===----------------------------------------------------------------------===//
+
#ifndef LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
#define LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp
index 4b3d5bee5631..2ed0ce1c79c5 100644
--- a/lib/AST/InheritViz.cpp
+++ b/lib/AST/InheritViz.cpp
@@ -90,8 +90,8 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
Out << " \"];\n";
// Display the base classes.
- const CXXRecordDecl *Decl
- = static_cast<const CXXRecordDecl *>(Type->getAs<RecordType>()->getDecl());
+ const auto *Decl =
+ static_cast<const CXXRecordDecl *>(Type->castAs<RecordType>()->getDecl());
for (const auto &Base : Decl->bases()) {
QualType CanonBaseType = Context.getCanonicalType(Base.getType());
diff --git a/lib/AST/Interp/Block.cpp b/lib/AST/Interp/Block.cpp
new file mode 100644
index 000000000000..5fc93eb39f4e
--- /dev/null
+++ b/lib/AST/Interp/Block.cpp
@@ -0,0 +1,87 @@
+//===--- Block.cpp - Allocated blocks for the interpreter -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the classes describing allocated blocks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Block.h"
+#include "Pointer.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+
+
+void Block::addPointer(Pointer *P) {
+ if (IsStatic)
+ return;
+ if (Pointers)
+ Pointers->Prev = P;
+ P->Next = Pointers;
+ P->Prev = nullptr;
+ Pointers = P;
+}
+
+void Block::removePointer(Pointer *P) {
+ if (IsStatic)
+ return;
+ if (Pointers == P)
+ Pointers = P->Next;
+ if (P->Prev)
+ P->Prev->Next = P->Next;
+ if (P->Next)
+ P->Next->Prev = P->Prev;
+}
+
+void Block::cleanup() {
+ if (Pointers == nullptr && IsDead)
+ (reinterpret_cast<DeadBlock *>(this + 1) - 1)->free();
+}
+
+void Block::movePointer(Pointer *From, Pointer *To) {
+ if (IsStatic)
+ return;
+ To->Prev = From->Prev;
+ if (To->Prev)
+ To->Prev->Next = To;
+ To->Next = From->Next;
+ if (To->Next)
+ To->Next->Prev = To;
+ if (Pointers == From)
+ Pointers = To;
+
+ From->Prev = nullptr;
+ From->Next = nullptr;
+}
+
+DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)
+ : Root(Root), B(Blk->Desc, Blk->IsStatic, Blk->IsExtern, /*isDead=*/true) {
+ // Add the block to the chain of dead blocks.
+ if (Root)
+ Root->Prev = this;
+
+ Next = Root;
+ Prev = nullptr;
+ Root = this;
+
+ // Transfer pointers.
+ B.Pointers = Blk->Pointers;
+ for (Pointer *P = Blk->Pointers; P; P = P->Next)
+ P->Pointee = &B;
+}
+
+void DeadBlock::free() {
+ if (Prev)
+ Prev->Next = Next;
+ if (Next)
+ Next->Prev = Prev;
+ if (Root == this)
+ Root = Next;
+ ::free(this);
+}
diff --git a/lib/AST/Interp/Block.h b/lib/AST/Interp/Block.h
new file mode 100644
index 000000000000..97fb9a3ca096
--- /dev/null
+++ b/lib/AST/Interp/Block.h
@@ -0,0 +1,140 @@
+//===--- Block.h - Allocated blocks for the interpreter ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the classes describing allocated blocks.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_BLOCK_H
+#define LLVM_CLANG_AST_INTERP_BLOCK_H
+
+#include "Descriptor.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ComparisonCategories.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace interp {
+class Block;
+class DeadBlock;
+class Context;
+class InterpState;
+class Pointer;
+class Function;
+enum PrimType : unsigned;
+
+/// A memory block, either on the stack or in the heap.
+///
+/// The storage described by the block immediately follows it in memory.
+class Block {
+public:
+ // Creates a new block.
+ Block(const llvm::Optional<unsigned> &DeclID, Descriptor *Desc,
+ bool IsStatic = false, bool IsExtern = false)
+ : DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {}
+
+ Block(Descriptor *Desc, bool IsStatic = false, bool IsExtern = false)
+ : DeclID((unsigned)-1), IsStatic(IsStatic), IsExtern(IsExtern),
+ Desc(Desc) {}
+
+ /// Returns the block's descriptor.
+ Descriptor *getDescriptor() const { return Desc; }
+ /// Checks if the block has any live pointers.
+ bool hasPointers() const { return Pointers; }
+ /// Checks if the block is extern.
+ bool isExtern() const { return IsExtern; }
+ /// Checks if the block has static storage duration.
+ bool isStatic() const { return IsStatic; }
+ /// Checks if the block is temporary.
+ bool isTemporary() const { return Desc->IsTemporary; }
+ /// Returns the size of the block.
+ InterpSize getSize() const { return Desc->getAllocSize(); }
+ /// Returns the declaration ID.
+ llvm::Optional<unsigned> getDeclID() const { return DeclID; }
+
+ /// Returns a pointer to the stored data.
+ char *data() { return reinterpret_cast<char *>(this + 1); }
+
+ /// Returns a view over the data.
+ template <typename T>
+ T &deref() { return *reinterpret_cast<T *>(data()); }
+
+ /// Invokes the constructor.
+ void invokeCtor() {
+ std::memset(data(), 0, getSize());
+ if (Desc->CtorFn)
+ Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable,
+ /*isActive=*/true, Desc);
+ }
+
+protected:
+ friend class Pointer;
+ friend class DeadBlock;
+ friend class InterpState;
+
+ Block(Descriptor *Desc, bool IsExtern, bool IsStatic, bool IsDead)
+ : IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true), Desc(Desc) {}
+
+ // Deletes a dead block at the end of its lifetime.
+ void cleanup();
+
+ // Pointer chain management.
+ void addPointer(Pointer *P);
+ void removePointer(Pointer *P);
+ void movePointer(Pointer *From, Pointer *To);
+
+ /// Start of the chain of pointers.
+ Pointer *Pointers = nullptr;
+ /// Unique identifier of the declaration.
+ llvm::Optional<unsigned> DeclID;
+ /// Flag indicating if the block has static storage duration.
+ bool IsStatic = false;
+ /// Flag indicating if the block is an extern.
+ bool IsExtern = false;
+ /// Flag indicating if the pointer is dead.
+ bool IsDead = false;
+ /// Pointer to the stack slot descriptor.
+ Descriptor *Desc;
+};
+
+/// Descriptor for a dead block.
+///
+/// Dead blocks are chained in a double-linked list to deallocate them
+/// whenever pointers become dead.
+class DeadBlock {
+public:
+ /// Copies the block.
+ DeadBlock(DeadBlock *&Root, Block *Blk);
+
+ /// Returns a pointer to the stored data.
+ char *data() { return B.data(); }
+
+private:
+ friend class Block;
+ friend class InterpState;
+
+ void free();
+
+ /// Root pointer of the list.
+ DeadBlock *&Root;
+ /// Previous block in the list.
+ DeadBlock *Prev;
+ /// Next block in the list.
+ DeadBlock *Next;
+
+ /// Actual block storing data and tracking pointers.
+ Block B;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/Boolean.h b/lib/AST/Interp/Boolean.h
new file mode 100644
index 000000000000..3e6c8b5da9f0
--- /dev/null
+++ b/lib/AST/Interp/Boolean.h
@@ -0,0 +1,148 @@
+//===--- Boolean.h - Wrapper for boolean types for the VM -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_BOOLEAN_H
+#define LLVM_CLANG_AST_INTERP_BOOLEAN_H
+
+#include <cstddef>
+#include <cstdint>
+#include "Integral.h"
+#include "clang/AST/APValue.h"
+#include "clang/AST/ComparisonCategories.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace interp {
+
+/// Wrapper around boolean types.
+class Boolean {
+ private:
+ /// Underlying boolean.
+ bool V;
+
+ /// Construct a wrapper from a boolean.
+ explicit Boolean(bool V) : V(V) {}
+
+ public:
+ /// Zero-initializes a boolean.
+ Boolean() : V(false) {}
+
+ bool operator<(Boolean RHS) const { return V < RHS.V; }
+ bool operator>(Boolean RHS) const { return V > RHS.V; }
+ bool operator<=(Boolean RHS) const { return V <= RHS.V; }
+ bool operator>=(Boolean RHS) const { return V >= RHS.V; }
+ bool operator==(Boolean RHS) const { return V == RHS.V; }
+ bool operator!=(Boolean RHS) const { return V != RHS.V; }
+
+ bool operator>(unsigned RHS) const { return static_cast<unsigned>(V) > RHS; }
+
+ Boolean operator-() const { return Boolean(V); }
+ Boolean operator~() const { return Boolean(true); }
+
+ explicit operator unsigned() const { return V; }
+ explicit operator int64_t() const { return V; }
+ explicit operator uint64_t() const { return V; }
+
+ APSInt toAPSInt() const {
+ return APSInt(APInt(1, static_cast<uint64_t>(V), false), true);
+ }
+ APSInt toAPSInt(unsigned NumBits) const {
+ return APSInt(toAPSInt().zextOrTrunc(NumBits), true);
+ }
+ APValue toAPValue() const { return APValue(toAPSInt()); }
+
+ Boolean toUnsigned() const { return *this; }
+
+ constexpr static unsigned bitWidth() { return true; }
+ bool isZero() const { return !V; }
+ bool isMin() const { return isZero(); }
+
+ constexpr static bool isMinusOne() { return false; }
+
+ constexpr static bool isSigned() { return false; }
+
+ constexpr static bool isNegative() { return false; }
+ constexpr static bool isPositive() { return !isNegative(); }
+
+ ComparisonCategoryResult compare(const Boolean &RHS) const {
+ return Compare(V, RHS.V);
+ }
+
+ unsigned countLeadingZeros() const { return V ? 0 : 1; }
+
+ Boolean truncate(unsigned TruncBits) const { return *this; }
+
+ void print(llvm::raw_ostream &OS) const { OS << (V ? "true" : "false"); }
+
+ static Boolean min(unsigned NumBits) { return Boolean(false); }
+ static Boolean max(unsigned NumBits) { return Boolean(true); }
+
+ template <typename T>
+ static typename std::enable_if<std::is_integral<T>::value, Boolean>::type
+ from(T Value) {
+ return Boolean(Value != 0);
+ }
+
+ template <unsigned SrcBits, bool SrcSign>
+ static typename std::enable_if<SrcBits != 0, Boolean>::type from(
+ Integral<SrcBits, SrcSign> Value) {
+ return Boolean(!Value.isZero());
+ }
+
+ template <bool SrcSign>
+ static Boolean from(Integral<0, SrcSign> Value) {
+ return Boolean(!Value.isZero());
+ }
+
+ static Boolean zero() { return from(false); }
+
+ template <typename T>
+ static Boolean from(T Value, unsigned NumBits) {
+ return Boolean(Value);
+ }
+
+ static bool inRange(int64_t Value, unsigned NumBits) {
+ return Value == 0 || Value == 1;
+ }
+
+ static bool increment(Boolean A, Boolean *R) {
+ *R = Boolean(true);
+ return false;
+ }
+
+ static bool decrement(Boolean A, Boolean *R) {
+ llvm_unreachable("Cannot decrement booleans");
+ }
+
+ static bool add(Boolean A, Boolean B, unsigned OpBits, Boolean *R) {
+ *R = Boolean(A.V || B.V);
+ return false;
+ }
+
+ static bool sub(Boolean A, Boolean B, unsigned OpBits, Boolean *R) {
+ *R = Boolean(A.V ^ B.V);
+ return false;
+ }
+
+ static bool mul(Boolean A, Boolean B, unsigned OpBits, Boolean *R) {
+ *R = Boolean(A.V && B.V);
+ return false;
+ }
+};
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Boolean &B) {
+ B.print(OS);
+ return OS;
+}
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/ByteCodeEmitter.cpp b/lib/AST/Interp/ByteCodeEmitter.cpp
new file mode 100644
index 000000000000..7a4569820a1d
--- /dev/null
+++ b/lib/AST/Interp/ByteCodeEmitter.cpp
@@ -0,0 +1,175 @@
+//===--- ByteCodeEmitter.cpp - Instruction emitter for the VM ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ByteCodeEmitter.h"
+#include "Context.h"
+#include "Opcode.h"
+#include "Program.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+using APSInt = llvm::APSInt;
+using Error = llvm::Error;
+
+Expected<Function *> ByteCodeEmitter::compileFunc(const FunctionDecl *F) {
+ // Do not try to compile undefined functions.
+ if (!F->isDefined(F) || (!F->hasBody() && F->willHaveBody()))
+ return nullptr;
+
+ // Set up argument indices.
+ unsigned ParamOffset = 0;
+ SmallVector<PrimType, 8> ParamTypes;
+ llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
+
+ // If the return is not a primitive, a pointer to the storage where the value
+ // is initialized in is passed as the first argument.
+ QualType Ty = F->getReturnType();
+ if (!Ty->isVoidType() && !Ctx.classify(Ty)) {
+ ParamTypes.push_back(PT_Ptr);
+ ParamOffset += align(primSize(PT_Ptr));
+ }
+
+ // Assign descriptors to all parameters.
+ // Composite objects are lowered to pointers.
+ for (const ParmVarDecl *PD : F->parameters()) {
+ PrimType Ty;
+ if (llvm::Optional<PrimType> T = Ctx.classify(PD->getType())) {
+ Ty = *T;
+ } else {
+ Ty = PT_Ptr;
+ }
+
+ Descriptor *Desc = P.createDescriptor(PD, Ty);
+ ParamDescriptors.insert({ParamOffset, {Ty, Desc}});
+ Params.insert({PD, ParamOffset});
+ ParamOffset += align(primSize(Ty));
+ ParamTypes.push_back(Ty);
+ }
+
+ // Create a handle over the emitted code.
+ Function *Func = P.createFunction(F, ParamOffset, std::move(ParamTypes),
+ std::move(ParamDescriptors));
+ // Compile the function body.
+ if (!F->isConstexpr() || !visitFunc(F)) {
+ // Return a dummy function if compilation failed.
+ if (BailLocation)
+ return llvm::make_error<ByteCodeGenError>(*BailLocation);
+ else
+ return Func;
+ } else {
+ // Create scopes from descriptors.
+ llvm::SmallVector<Scope, 2> Scopes;
+ for (auto &DS : Descriptors) {
+ Scopes.emplace_back(std::move(DS));
+ }
+
+ // Set the function's code.
+ Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
+ std::move(Scopes));
+ return Func;
+ }
+}
+
+Scope::Local ByteCodeEmitter::createLocal(Descriptor *D) {
+ NextLocalOffset += sizeof(Block);
+ unsigned Location = NextLocalOffset;
+ NextLocalOffset += align(D->getAllocSize());
+ return {Location, D};
+}
+
+void ByteCodeEmitter::emitLabel(LabelTy Label) {
+ const size_t Target = Code.size();
+ LabelOffsets.insert({Label, Target});
+ auto It = LabelRelocs.find(Label);
+ if (It != LabelRelocs.end()) {
+ for (unsigned Reloc : It->second) {
+ using namespace llvm::support;
+
+ /// Rewrite the operand of all jumps to this label.
+ void *Location = Code.data() + Reloc - sizeof(int32_t);
+ const int32_t Offset = Target - static_cast<int64_t>(Reloc);
+ endian::write<int32_t, endianness::native, 1>(Location, Offset);
+ }
+ LabelRelocs.erase(It);
+ }
+}
+
+int32_t ByteCodeEmitter::getOffset(LabelTy Label) {
+ // Compute the PC offset which the jump is relative to.
+ const int64_t Position = Code.size() + sizeof(Opcode) + sizeof(int32_t);
+
+ // If target is known, compute jump offset.
+ auto It = LabelOffsets.find(Label);
+ if (It != LabelOffsets.end()) {
+ return It->second - Position;
+ }
+
+ // Otherwise, record relocation and return dummy offset.
+ LabelRelocs[Label].push_back(Position);
+ return 0ull;
+}
+
+bool ByteCodeEmitter::bail(const SourceLocation &Loc) {
+ if (!BailLocation)
+ BailLocation = Loc;
+ return false;
+}
+
+template <typename... Tys>
+bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
+ bool Success = true;
+
+ /// Helper to write bytecode and bail out if 32-bit offsets become invalid.
+ auto emit = [this, &Success](const char *Data, size_t Size) {
+ if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
+ Success = false;
+ return;
+ }
+ Code.insert(Code.end(), Data, Data + Size);
+ };
+
+ /// The opcode is followed by arguments. The source info is
+ /// attached to the address after the opcode.
+ emit(reinterpret_cast<const char *>(&Op), sizeof(Opcode));
+ if (SI)
+ SrcMap.emplace_back(Code.size(), SI);
+
+ /// The initializer list forces the expression to be evaluated
+ /// for each argument in the variadic template, in order.
+ (void)std::initializer_list<int>{
+ (emit(reinterpret_cast<const char *>(&Args), sizeof(Args)), 0)...};
+
+ return Success;
+}
+
+bool ByteCodeEmitter::jumpTrue(const LabelTy &Label) {
+ return emitJt(getOffset(Label), SourceInfo{});
+}
+
+bool ByteCodeEmitter::jumpFalse(const LabelTy &Label) {
+ return emitJf(getOffset(Label), SourceInfo{});
+}
+
+bool ByteCodeEmitter::jump(const LabelTy &Label) {
+ return emitJmp(getOffset(Label), SourceInfo{});
+}
+
+bool ByteCodeEmitter::fallthrough(const LabelTy &Label) {
+ emitLabel(Label);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Opcode emitters
+//===----------------------------------------------------------------------===//
+
+#define GET_LINK_IMPL
+#include "Opcodes.inc"
+#undef GET_LINK_IMPL
diff --git a/lib/AST/Interp/ByteCodeEmitter.h b/lib/AST/Interp/ByteCodeEmitter.h
new file mode 100644
index 000000000000..03452a350c96
--- /dev/null
+++ b/lib/AST/Interp/ByteCodeEmitter.h
@@ -0,0 +1,112 @@
+//===--- ByteCodeEmitter.h - Instruction emitter for the VM ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the instruction emitters.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_LINKEMITTER_H
+#define LLVM_CLANG_AST_INTERP_LINKEMITTER_H
+
+#include "ByteCodeGenError.h"
+#include "Context.h"
+#include "InterpStack.h"
+#include "InterpState.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "Source.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace interp {
+class Context;
+class SourceInfo;
+enum Opcode : uint32_t;
+
+/// An emitter which links the program to bytecode for later use.
+class ByteCodeEmitter {
+protected:
+ using LabelTy = uint32_t;
+ using AddrTy = uintptr_t;
+ using Local = Scope::Local;
+
+public:
+ /// Compiles the function into the module.
+ llvm::Expected<Function *> compileFunc(const FunctionDecl *F);
+
+protected:
+ ByteCodeEmitter(Context &Ctx, Program &P) : Ctx(Ctx), P(P) {}
+
+ virtual ~ByteCodeEmitter() {}
+
+ /// Define a label.
+ void emitLabel(LabelTy Label);
+ /// Create a label.
+ LabelTy getLabel() { return ++NextLabel; }
+
+ /// Methods implemented by the compiler.
+ virtual bool visitFunc(const FunctionDecl *E) = 0;
+ virtual bool visitExpr(const Expr *E) = 0;
+ virtual bool visitDecl(const VarDecl *E) = 0;
+
+ /// Bails out if a given node cannot be compiled.
+ bool bail(const Stmt *S) { return bail(S->getBeginLoc()); }
+ bool bail(const Decl *D) { return bail(D->getBeginLoc()); }
+ bool bail(const SourceLocation &Loc);
+
+ /// Emits jumps.
+ bool jumpTrue(const LabelTy &Label);
+ bool jumpFalse(const LabelTy &Label);
+ bool jump(const LabelTy &Label);
+ bool fallthrough(const LabelTy &Label);
+
+ /// Callback for local registration.
+ Local createLocal(Descriptor *D);
+
+ /// Parameter indices.
+ llvm::DenseMap<const ParmVarDecl *, unsigned> Params;
+ /// Local descriptors.
+ llvm::SmallVector<SmallVector<Local, 8>, 2> Descriptors;
+
+private:
+ /// Current compilation context.
+ Context &Ctx;
+ /// Program to link to.
+ Program &P;
+ /// Index of the next available label.
+ LabelTy NextLabel = 0;
+ /// Offset of the next local variable.
+ unsigned NextLocalOffset = 0;
+ /// Location of a failure.
+ llvm::Optional<SourceLocation> BailLocation;
+ /// Label information for linker.
+ llvm::DenseMap<LabelTy, unsigned> LabelOffsets;
+ /// Location of label relocations.
+ llvm::DenseMap<LabelTy, llvm::SmallVector<unsigned, 5>> LabelRelocs;
+ /// Program code.
+ std::vector<char> Code;
+ /// Opcode to expression mapping.
+ SourceMap SrcMap;
+
+ /// Returns the offset for a jump or records a relocation.
+ int32_t getOffset(LabelTy Label);
+
+ /// Emits an opcode.
+ template <typename... Tys>
+ bool emitOp(Opcode Op, const Tys &... Args, const SourceInfo &L);
+
+protected:
+#define GET_LINK_PROTO
+#include "Opcodes.inc"
+#undef GET_LINK_PROTO
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/ByteCodeExprGen.cpp b/lib/AST/Interp/ByteCodeExprGen.cpp
new file mode 100644
index 000000000000..5c8cb4274260
--- /dev/null
+++ b/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -0,0 +1,580 @@
+//===--- ByteCodeExprGen.cpp - Code generator for expressions ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ByteCodeExprGen.h"
+#include "ByteCodeEmitter.h"
+#include "ByteCodeGenError.h"
+#include "Context.h"
+#include "Function.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "State.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+using APSInt = llvm::APSInt;
+template <typename T> using Expected = llvm::Expected<T>;
+template <typename T> using Optional = llvm::Optional<T>;
+
+namespace clang {
+namespace interp {
+
+/// Scope used to handle temporaries in toplevel variable declarations.
+template <class Emitter> class DeclScope final : public LocalScope<Emitter> {
+public:
+ DeclScope(ByteCodeExprGen<Emitter> *Ctx, const VarDecl *VD)
+ : LocalScope<Emitter>(Ctx), Scope(Ctx->P, VD) {}
+
+ void addExtended(const Scope::Local &Local) override {
+ return this->addLocal(Local);
+ }
+
+private:
+ Program::DeclScope Scope;
+};
+
+/// Scope used to handle initialization methods.
+template <class Emitter> class OptionScope {
+public:
+ using InitFnRef = typename ByteCodeExprGen<Emitter>::InitFnRef;
+ using ChainedInitFnRef = std::function<bool(InitFnRef)>;
+
+ /// Root constructor, compiling or discarding primitives.
+ OptionScope(ByteCodeExprGen<Emitter> *Ctx, bool NewDiscardResult)
+ : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
+ OldInitFn(std::move(Ctx->InitFn)) {
+ Ctx->DiscardResult = NewDiscardResult;
+ Ctx->InitFn = llvm::Optional<InitFnRef>{};
+ }
+
+ /// Root constructor, setting up compilation state.
+ OptionScope(ByteCodeExprGen<Emitter> *Ctx, InitFnRef NewInitFn)
+ : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
+ OldInitFn(std::move(Ctx->InitFn)) {
+ Ctx->DiscardResult = true;
+ Ctx->InitFn = NewInitFn;
+ }
+
+ /// Extends the chain of initialisation pointers.
+ OptionScope(ByteCodeExprGen<Emitter> *Ctx, ChainedInitFnRef NewInitFn)
+ : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
+ OldInitFn(std::move(Ctx->InitFn)) {
+ assert(OldInitFn && "missing initializer");
+ Ctx->InitFn = [this, NewInitFn] { return NewInitFn(*OldInitFn); };
+ }
+
+ ~OptionScope() {
+ Ctx->DiscardResult = OldDiscardResult;
+ Ctx->InitFn = std::move(OldInitFn);
+ }
+
+private:
+ /// Parent context.
+ ByteCodeExprGen<Emitter> *Ctx;
+ /// Old discard flag to restore.
+ bool OldDiscardResult;
+ /// Old pointer emitter to restore.
+ llvm::Optional<InitFnRef> OldInitFn;
+};
+
+} // namespace interp
+} // namespace clang
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
+ auto *SubExpr = CE->getSubExpr();
+ switch (CE->getCastKind()) {
+
+ case CK_LValueToRValue: {
+ return dereference(
+ CE->getSubExpr(), DerefKind::Read,
+ [](PrimType) {
+ // Value loaded - nothing to do here.
+ return true;
+ },
+ [this, CE](PrimType T) {
+ // Pointer on stack - dereference it.
+ if (!this->emitLoadPop(T, CE))
+ return false;
+ return DiscardResult ? this->emitPop(T, CE) : true;
+ });
+ }
+
+ case CK_ArrayToPointerDecay:
+ case CK_AtomicToNonAtomic:
+ case CK_ConstructorConversion:
+ case CK_FunctionToPointerDecay:
+ case CK_NonAtomicToAtomic:
+ case CK_NoOp:
+ case CK_UserDefinedConversion:
+ return this->Visit(SubExpr);
+
+ case CK_ToVoid:
+ return discard(SubExpr);
+
+ default: {
+ // TODO: implement other casts.
+ return this->bail(CE);
+ }
+ }
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitIntegerLiteral(const IntegerLiteral *LE) {
+ if (DiscardResult)
+ return true;
+
+ auto Val = LE->getValue();
+ QualType LitTy = LE->getType();
+ if (Optional<PrimType> T = classify(LitTy))
+ return emitConst(*T, getIntWidth(LitTy), LE->getValue(), LE);
+ return this->bail(LE);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitParenExpr(const ParenExpr *PE) {
+ return this->Visit(PE->getSubExpr());
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
+ const Expr *LHS = BO->getLHS();
+ const Expr *RHS = BO->getRHS();
+
+ // Deal with operations which have composite or void types.
+ switch (BO->getOpcode()) {
+ case BO_Comma:
+ if (!discard(LHS))
+ return false;
+ if (!this->Visit(RHS))
+ return false;
+ return true;
+ default:
+ break;
+ }
+
+ // Typecheck the args.
+ Optional<PrimType> LT = classify(LHS->getType());
+ Optional<PrimType> RT = classify(RHS->getType());
+ if (!LT || !RT) {
+ return this->bail(BO);
+ }
+
+ if (Optional<PrimType> T = classify(BO->getType())) {
+ if (!visit(LHS))
+ return false;
+ if (!visit(RHS))
+ return false;
+
+ auto Discard = [this, T, BO](bool Result) {
+ if (!Result)
+ return false;
+ return DiscardResult ? this->emitPop(*T, BO) : true;
+ };
+
+ switch (BO->getOpcode()) {
+ case BO_EQ:
+ return Discard(this->emitEQ(*LT, BO));
+ case BO_NE:
+ return Discard(this->emitNE(*LT, BO));
+ case BO_LT:
+ return Discard(this->emitLT(*LT, BO));
+ case BO_LE:
+ return Discard(this->emitLE(*LT, BO));
+ case BO_GT:
+ return Discard(this->emitGT(*LT, BO));
+ case BO_GE:
+ return Discard(this->emitGE(*LT, BO));
+ case BO_Sub:
+ return Discard(this->emitSub(*T, BO));
+ case BO_Add:
+ return Discard(this->emitAdd(*T, BO));
+ case BO_Mul:
+ return Discard(this->emitMul(*T, BO));
+ default:
+ return this->bail(BO);
+ }
+ }
+
+ return this->bail(BO);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
+ OptionScope<Emitter> Scope(this, /*discardResult=*/true);
+ return this->Visit(E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visit(const Expr *E) {
+ OptionScope<Emitter> Scope(this, /*discardResult=*/false);
+ return this->Visit(E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitBool(const Expr *E) {
+ if (Optional<PrimType> T = classify(E->getType())) {
+ return visit(E);
+ } else {
+ return this->bail(E);
+ }
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitZeroInitializer(PrimType T, const Expr *E) {
+ switch (T) {
+ case PT_Bool:
+ return this->emitZeroBool(E);
+ case PT_Sint8:
+ return this->emitZeroSint8(E);
+ case PT_Uint8:
+ return this->emitZeroUint8(E);
+ case PT_Sint16:
+ return this->emitZeroSint16(E);
+ case PT_Uint16:
+ return this->emitZeroUint16(E);
+ case PT_Sint32:
+ return this->emitZeroSint32(E);
+ case PT_Uint32:
+ return this->emitZeroUint32(E);
+ case PT_Sint64:
+ return this->emitZeroSint64(E);
+ case PT_Uint64:
+ return this->emitZeroUint64(E);
+ case PT_Ptr:
+ return this->emitNullPtr(E);
+ }
+ llvm_unreachable("unknown primitive type");
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::dereference(
+ const Expr *LV, DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
+ llvm::function_ref<bool(PrimType)> Indirect) {
+ if (Optional<PrimType> T = classify(LV->getType())) {
+ if (!LV->refersToBitField()) {
+ // Only primitive, non bit-field types can be dereferenced directly.
+ if (auto *DE = dyn_cast<DeclRefExpr>(LV)) {
+ if (!DE->getDecl()->getType()->isReferenceType()) {
+ if (auto *PD = dyn_cast<ParmVarDecl>(DE->getDecl()))
+ return dereferenceParam(LV, *T, PD, AK, Direct, Indirect);
+ if (auto *VD = dyn_cast<VarDecl>(DE->getDecl()))
+ return dereferenceVar(LV, *T, VD, AK, Direct, Indirect);
+ }
+ }
+ }
+
+ if (!visit(LV))
+ return false;
+ return Indirect(*T);
+ }
+
+ return false;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::dereferenceParam(
+ const Expr *LV, PrimType T, const ParmVarDecl *PD, DerefKind AK,
+ llvm::function_ref<bool(PrimType)> Direct,
+ llvm::function_ref<bool(PrimType)> Indirect) {
+ auto It = this->Params.find(PD);
+ if (It != this->Params.end()) {
+ unsigned Idx = It->second;
+ switch (AK) {
+ case DerefKind::Read:
+ return DiscardResult ? true : this->emitGetParam(T, Idx, LV);
+
+ case DerefKind::Write:
+ if (!Direct(T))
+ return false;
+ if (!this->emitSetParam(T, Idx, LV))
+ return false;
+ return DiscardResult ? true : this->emitGetPtrParam(Idx, LV);
+
+ case DerefKind::ReadWrite:
+ if (!this->emitGetParam(T, Idx, LV))
+ return false;
+ if (!Direct(T))
+ return false;
+ if (!this->emitSetParam(T, Idx, LV))
+ return false;
+ return DiscardResult ? true : this->emitGetPtrParam(Idx, LV);
+ }
+ return true;
+ }
+
+ // If the param is a pointer, we can dereference a dummy value.
+ if (!DiscardResult && T == PT_Ptr && AK == DerefKind::Read) {
+ if (auto Idx = P.getOrCreateDummy(PD))
+ return this->emitGetPtrGlobal(*Idx, PD);
+ return false;
+ }
+
+ // Value cannot be produced - try to emit pointer and do stuff with it.
+ return visit(LV) && Indirect(T);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::dereferenceVar(
+ const Expr *LV, PrimType T, const VarDecl *VD, DerefKind AK,
+ llvm::function_ref<bool(PrimType)> Direct,
+ llvm::function_ref<bool(PrimType)> Indirect) {
+ auto It = Locals.find(VD);
+ if (It != Locals.end()) {
+ const auto &L = It->second;
+ switch (AK) {
+ case DerefKind::Read:
+ if (!this->emitGetLocal(T, L.Offset, LV))
+ return false;
+ return DiscardResult ? this->emitPop(T, LV) : true;
+
+ case DerefKind::Write:
+ if (!Direct(T))
+ return false;
+ if (!this->emitSetLocal(T, L.Offset, LV))
+ return false;
+ return DiscardResult ? true : this->emitGetPtrLocal(L.Offset, LV);
+
+ case DerefKind::ReadWrite:
+ if (!this->emitGetLocal(T, L.Offset, LV))
+ return false;
+ if (!Direct(T))
+ return false;
+ if (!this->emitSetLocal(T, L.Offset, LV))
+ return false;
+ return DiscardResult ? true : this->emitGetPtrLocal(L.Offset, LV);
+ }
+ } else if (auto Idx = getGlobalIdx(VD)) {
+ switch (AK) {
+ case DerefKind::Read:
+ if (!this->emitGetGlobal(T, *Idx, LV))
+ return false;
+ return DiscardResult ? this->emitPop(T, LV) : true;
+
+ case DerefKind::Write:
+ if (!Direct(T))
+ return false;
+ if (!this->emitSetGlobal(T, *Idx, LV))
+ return false;
+ return DiscardResult ? true : this->emitGetPtrGlobal(*Idx, LV);
+
+ case DerefKind::ReadWrite:
+ if (!this->emitGetGlobal(T, *Idx, LV))
+ return false;
+ if (!Direct(T))
+ return false;
+ if (!this->emitSetGlobal(T, *Idx, LV))
+ return false;
+ return DiscardResult ? true : this->emitGetPtrGlobal(*Idx, LV);
+ }
+ }
+
+ // If the declaration is a constant value, emit it here even
+ // though the declaration was not evaluated in the current scope.
+ // The access mode can only be read in this case.
+ if (!DiscardResult && AK == DerefKind::Read) {
+ if (VD->hasLocalStorage() && VD->hasInit() && !VD->isConstexpr()) {
+ QualType VT = VD->getType();
+ if (VT.isConstQualified() && VT->isFundamentalType())
+ return this->Visit(VD->getInit());
+ }
+ }
+
+ // Value cannot be produced - try to emit pointer.
+ return visit(LV) && Indirect(T);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::emitConst(PrimType T, unsigned NumBits,
+ const APInt &Value, const Expr *E) {
+ switch (T) {
+ case PT_Sint8:
+ return this->emitConstSint8(Value.getSExtValue(), E);
+ case PT_Uint8:
+ return this->emitConstUint8(Value.getZExtValue(), E);
+ case PT_Sint16:
+ return this->emitConstSint16(Value.getSExtValue(), E);
+ case PT_Uint16:
+ return this->emitConstUint16(Value.getZExtValue(), E);
+ case PT_Sint32:
+ return this->emitConstSint32(Value.getSExtValue(), E);
+ case PT_Uint32:
+ return this->emitConstUint32(Value.getZExtValue(), E);
+ case PT_Sint64:
+ return this->emitConstSint64(Value.getSExtValue(), E);
+ case PT_Uint64:
+ return this->emitConstUint64(Value.getZExtValue(), E);
+ case PT_Bool:
+ return this->emitConstBool(Value.getBoolValue(), E);
+ case PT_Ptr:
+ llvm_unreachable("Invalid integral type");
+ break;
+ }
+ llvm_unreachable("unknown primitive type");
+}
+
+template <class Emitter>
+unsigned ByteCodeExprGen<Emitter>::allocateLocalPrimitive(DeclTy &&Src,
+ PrimType Ty,
+ bool IsConst,
+ bool IsExtended) {
+ Descriptor *D = P.createDescriptor(Src, Ty, IsConst, Src.is<const Expr *>());
+ Scope::Local Local = this->createLocal(D);
+ if (auto *VD = dyn_cast_or_null<ValueDecl>(Src.dyn_cast<const Decl *>()))
+ Locals.insert({VD, Local});
+ VarScope->add(Local, IsExtended);
+ return Local.Offset;
+}
+
+template <class Emitter>
+llvm::Optional<unsigned>
+ByteCodeExprGen<Emitter>::allocateLocal(DeclTy &&Src, bool IsExtended) {
+ QualType Ty;
+
+ const ValueDecl *Key = nullptr;
+ bool IsTemporary = false;
+ if (auto *VD = dyn_cast_or_null<ValueDecl>(Src.dyn_cast<const Decl *>())) {
+ Key = VD;
+ Ty = VD->getType();
+ }
+ if (auto *E = Src.dyn_cast<const Expr *>()) {
+ IsTemporary = true;
+ Ty = E->getType();
+ }
+
+ Descriptor *D = P.createDescriptor(Src, Ty.getTypePtr(),
+ Ty.isConstQualified(), IsTemporary);
+ if (!D)
+ return {};
+
+ Scope::Local Local = this->createLocal(D);
+ if (Key)
+ Locals.insert({Key, Local});
+ VarScope->add(Local, IsExtended);
+ return Local.Offset;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitInitializer(
+ const Expr *Init, InitFnRef InitFn) {
+ OptionScope<Emitter> Scope(this, InitFn);
+ return this->Visit(Init);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::getPtrVarDecl(const VarDecl *VD, const Expr *E) {
+ // Generate a pointer to the local, loading refs.
+ if (Optional<unsigned> Idx = getGlobalIdx(VD)) {
+ if (VD->getType()->isReferenceType())
+ return this->emitGetGlobalPtr(*Idx, E);
+ else
+ return this->emitGetPtrGlobal(*Idx, E);
+ }
+ return this->bail(VD);
+}
+
+template <class Emitter>
+llvm::Optional<unsigned>
+ByteCodeExprGen<Emitter>::getGlobalIdx(const VarDecl *VD) {
+ if (VD->isConstexpr()) {
+ // Constexpr decl - it must have already been defined.
+ return P.getGlobal(VD);
+ }
+ if (!VD->hasLocalStorage()) {
+ // Not constexpr, but a global var - can have pointer taken.
+ Program::DeclScope Scope(P, VD);
+ return P.getOrCreateGlobal(VD);
+ }
+ return {};
+}
+
+template <class Emitter>
+const RecordType *ByteCodeExprGen<Emitter>::getRecordTy(QualType Ty) {
+ if (auto *PT = dyn_cast<PointerType>(Ty))
+ return PT->getPointeeType()->getAs<RecordType>();
+ else
+ return Ty->getAs<RecordType>();
+}
+
+template <class Emitter>
+Record *ByteCodeExprGen<Emitter>::getRecord(QualType Ty) {
+ if (auto *RecordTy = getRecordTy(Ty)) {
+ return getRecord(RecordTy->getDecl());
+ }
+ return nullptr;
+}
+
+template <class Emitter>
+Record *ByteCodeExprGen<Emitter>::getRecord(const RecordDecl *RD) {
+ return P.getOrCreateRecord(RD);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitExpr(const Expr *Exp) {
+ ExprScope<Emitter> RootScope(this);
+ if (!visit(Exp))
+ return false;
+
+ if (Optional<PrimType> T = classify(Exp))
+ return this->emitRet(*T, Exp);
+ else
+ return this->emitRetValue(Exp);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD) {
+ const Expr *Init = VD->getInit();
+
+ if (Optional<unsigned> I = P.createGlobal(VD)) {
+ if (Optional<PrimType> T = classify(VD->getType())) {
+ {
+ // Primitive declarations - compute the value and set it.
+ DeclScope<Emitter> LocalScope(this, VD);
+ if (!visit(Init))
+ return false;
+ }
+
+ // If the declaration is global, save the value for later use.
+ if (!this->emitDup(*T, VD))
+ return false;
+ if (!this->emitInitGlobal(*T, *I, VD))
+ return false;
+ return this->emitRet(*T, VD);
+ } else {
+ {
+ // Composite declarations - allocate storage and initialize it.
+ DeclScope<Emitter> LocalScope(this, VD);
+ if (!visitGlobalInitializer(Init, *I))
+ return false;
+ }
+
+ // Return a pointer to the global.
+ if (!this->emitGetPtrGlobal(*I, VD))
+ return false;
+ return this->emitRetValue(VD);
+ }
+ }
+
+ return this->bail(VD);
+}
+
+template <class Emitter>
+void ByteCodeExprGen<Emitter>::emitCleanup() {
+ for (VariableScope<Emitter> *C = VarScope; C; C = C->getParent())
+ C->emitDestruction();
+}
+
+namespace clang {
+namespace interp {
+
+template class ByteCodeExprGen<ByteCodeEmitter>;
+template class ByteCodeExprGen<EvalEmitter>;
+
+} // namespace interp
+} // namespace clang
diff --git a/lib/AST/Interp/ByteCodeExprGen.h b/lib/AST/Interp/ByteCodeExprGen.h
new file mode 100644
index 000000000000..1d0e34fc991f
--- /dev/null
+++ b/lib/AST/Interp/ByteCodeExprGen.h
@@ -0,0 +1,331 @@
+//===--- ByteCodeExprGen.h - Code generator for expressions -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the constexpr bytecode compiler.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
+#define LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
+
+#include "ByteCodeEmitter.h"
+#include "EvalEmitter.h"
+#include "Pointer.h"
+#include "PrimType.h"
+#include "Record.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/Optional.h"
+
+namespace clang {
+class QualType;
+
+namespace interp {
+class Function;
+class State;
+
+template <class Emitter> class LocalScope;
+template <class Emitter> class RecordScope;
+template <class Emitter> class VariableScope;
+template <class Emitter> class DeclScope;
+template <class Emitter> class OptionScope;
+
+/// Compilation context for expressions.
+template <class Emitter>
+class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
+ public Emitter {
+protected:
+ // Emitters for opcodes of various arities.
+ using NullaryFn = bool (ByteCodeExprGen::*)(const SourceInfo &);
+ using UnaryFn = bool (ByteCodeExprGen::*)(PrimType, const SourceInfo &);
+ using BinaryFn = bool (ByteCodeExprGen::*)(PrimType, PrimType,
+ const SourceInfo &);
+
+ // Aliases for types defined in the emitter.
+ using LabelTy = typename Emitter::LabelTy;
+ using AddrTy = typename Emitter::AddrTy;
+
+ // Reference to a function generating the pointer of an initialized object.s
+ using InitFnRef = std::function<bool()>;
+
+ /// Current compilation context.
+ Context &Ctx;
+ /// Program to link to.
+ Program &P;
+
+public:
+ /// Initializes the compiler and the backend emitter.
+ template <typename... Tys>
+ ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
+ : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
+
+ // Expression visitors - result returned on stack.
+ bool VisitCastExpr(const CastExpr *E);
+ bool VisitIntegerLiteral(const IntegerLiteral *E);
+ bool VisitParenExpr(const ParenExpr *E);
+ bool VisitBinaryOperator(const BinaryOperator *E);
+
+protected:
+ bool visitExpr(const Expr *E) override;
+ bool visitDecl(const VarDecl *VD) override;
+
+protected:
+ /// Emits scope cleanup instructions.
+ void emitCleanup();
+
+ /// Returns a record type from a record or pointer type.
+ const RecordType *getRecordTy(QualType Ty);
+
+ /// Returns a record from a record or pointer type.
+ Record *getRecord(QualType Ty);
+ Record *getRecord(const RecordDecl *RD);
+
+ /// Returns the size int bits of an integer.
+ unsigned getIntWidth(QualType Ty) {
+ auto &ASTContext = Ctx.getASTContext();
+ return ASTContext.getIntWidth(Ty);
+ }
+
+ /// Returns the value of CHAR_BIT.
+ unsigned getCharBit() const {
+ auto &ASTContext = Ctx.getASTContext();
+ return ASTContext.getTargetInfo().getCharWidth();
+ }
+
+ /// Classifies a type.
+ llvm::Optional<PrimType> classify(const Expr *E) const {
+ return E->isGLValue() ? PT_Ptr : classify(E->getType());
+ }
+ llvm::Optional<PrimType> classify(QualType Ty) const {
+ return Ctx.classify(Ty);
+ }
+
+ /// Checks if a pointer needs adjustment.
+ bool needsAdjust(QualType Ty) const {
+ return true;
+ }
+
+ /// Classifies a known primitive type
+ PrimType classifyPrim(QualType Ty) const {
+ if (auto T = classify(Ty)) {
+ return *T;
+ }
+ llvm_unreachable("not a primitive type");
+ }
+
+ /// Evaluates an expression for side effects and discards the result.
+ bool discard(const Expr *E);
+ /// Evaluates an expression and places result on stack.
+ bool visit(const Expr *E);
+ /// Compiles an initializer for a local.
+ bool visitInitializer(const Expr *E, InitFnRef GenPtr);
+
+ /// Visits an expression and converts it to a boolean.
+ bool visitBool(const Expr *E);
+
+ /// Visits an initializer for a local.
+ bool visitLocalInitializer(const Expr *Init, unsigned I) {
+ return visitInitializer(Init, [this, I, Init] {
+ return this->emitGetPtrLocal(I, Init);
+ });
+ }
+
+ /// Visits an initializer for a global.
+ bool visitGlobalInitializer(const Expr *Init, unsigned I) {
+ return visitInitializer(Init, [this, I, Init] {
+ return this->emitGetPtrGlobal(I, Init);
+ });
+ }
+
+ /// Visits a delegated initializer.
+ bool visitThisInitializer(const Expr *I) {
+ return visitInitializer(I, [this, I] { return this->emitThis(I); });
+ }
+
+ /// Creates a local primitive value.
+ unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsMutable,
+ bool IsExtended = false);
+
+ /// Allocates a space storing a local given its type.
+ llvm::Optional<unsigned> allocateLocal(DeclTy &&Decl,
+ bool IsExtended = false);
+
+private:
+ friend class VariableScope<Emitter>;
+ friend class LocalScope<Emitter>;
+ friend class RecordScope<Emitter>;
+ friend class DeclScope<Emitter>;
+ friend class OptionScope<Emitter>;
+
+ /// Emits a zero initializer.
+ bool visitZeroInitializer(PrimType T, const Expr *E);
+
+ enum class DerefKind {
+ /// Value is read and pushed to stack.
+ Read,
+ /// Direct method generates a value which is written. Returns pointer.
+ Write,
+ /// Direct method receives the value, pushes mutated value. Returns pointer.
+ ReadWrite,
+ };
+
+ /// Method to directly load a value. If the value can be fetched directly,
+ /// the direct handler is called. Otherwise, a pointer is left on the stack
+ /// and the indirect handler is expected to operate on that.
+ bool dereference(const Expr *LV, DerefKind AK,
+ llvm::function_ref<bool(PrimType)> Direct,
+ llvm::function_ref<bool(PrimType)> Indirect);
+ bool dereferenceParam(const Expr *LV, PrimType T, const ParmVarDecl *PD,
+ DerefKind AK,
+ llvm::function_ref<bool(PrimType)> Direct,
+ llvm::function_ref<bool(PrimType)> Indirect);
+ bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD,
+ DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
+ llvm::function_ref<bool(PrimType)> Indirect);
+
+ /// Emits an APInt constant.
+ bool emitConst(PrimType T, unsigned NumBits, const llvm::APInt &Value,
+ const Expr *E);
+
+ /// Emits an integer constant.
+ template <typename T> bool emitConst(const Expr *E, T Value) {
+ QualType Ty = E->getType();
+ unsigned NumBits = getIntWidth(Ty);
+ APInt WrappedValue(NumBits, Value, std::is_signed<T>::value);
+ return emitConst(*Ctx.classify(Ty), NumBits, WrappedValue, E);
+ }
+
+ /// Returns a pointer to a variable declaration.
+ bool getPtrVarDecl(const VarDecl *VD, const Expr *E);
+
+ /// Returns the index of a global.
+ llvm::Optional<unsigned> getGlobalIdx(const VarDecl *VD);
+
+ /// Emits the initialized pointer.
+ bool emitInitFn() {
+ assert(InitFn && "missing initializer");
+ return (*InitFn)();
+ }
+
+protected:
+ /// Variable to storage mapping.
+ llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
+
+ /// OpaqueValueExpr to location mapping.
+ llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs;
+
+ /// Current scope.
+ VariableScope<Emitter> *VarScope = nullptr;
+
+ /// Current argument index.
+ llvm::Optional<uint64_t> ArrayIndex;
+
+ /// Flag indicating if return value is to be discarded.
+ bool DiscardResult = false;
+
+ /// Expression being initialized.
+ llvm::Optional<InitFnRef> InitFn = {};
+};
+
+extern template class ByteCodeExprGen<ByteCodeEmitter>;
+extern template class ByteCodeExprGen<EvalEmitter>;
+
+/// Scope chain managing the variable lifetimes.
+template <class Emitter> class VariableScope {
+public:
+ virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
+
+ void add(const Scope::Local &Local, bool IsExtended) {
+ if (IsExtended)
+ this->addExtended(Local);
+ else
+ this->addLocal(Local);
+ }
+
+ virtual void addLocal(const Scope::Local &Local) {
+ if (this->Parent)
+ this->Parent->addLocal(Local);
+ }
+
+ virtual void addExtended(const Scope::Local &Local) {
+ if (this->Parent)
+ this->Parent->addExtended(Local);
+ }
+
+ virtual void emitDestruction() {}
+
+ VariableScope *getParent() { return Parent; }
+
+protected:
+ VariableScope(ByteCodeExprGen<Emitter> *Ctx)
+ : Ctx(Ctx), Parent(Ctx->VarScope) {
+ Ctx->VarScope = this;
+ }
+
+ /// ByteCodeExprGen instance.
+ ByteCodeExprGen<Emitter> *Ctx;
+ /// Link to the parent scope.
+ VariableScope *Parent;
+};
+
+/// Scope for local variables.
+///
+/// When the scope is destroyed, instructions are emitted to tear down
+/// all variables declared in this scope.
+template <class Emitter> class LocalScope : public VariableScope<Emitter> {
+public:
+ LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {}
+
+ ~LocalScope() override { this->emitDestruction(); }
+
+ void addLocal(const Scope::Local &Local) override {
+ if (!Idx.hasValue()) {
+ Idx = this->Ctx->Descriptors.size();
+ this->Ctx->Descriptors.emplace_back();
+ }
+
+ this->Ctx->Descriptors[*Idx].emplace_back(Local);
+ }
+
+ void emitDestruction() override {
+ if (!Idx.hasValue())
+ return;
+ this->Ctx->emitDestroy(*Idx, SourceInfo{});
+ }
+
+protected:
+ /// Index of the scope in the chain.
+ Optional<unsigned> Idx;
+};
+
+/// Scope for storage declared in a compound statement.
+template <class Emitter> class BlockScope final : public LocalScope<Emitter> {
+public:
+ BlockScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
+
+ void addExtended(const Scope::Local &Local) override {
+ llvm_unreachable("Cannot create temporaries in full scopes");
+ }
+};
+
+/// Expression scope which tracks potentially lifetime extended
+/// temporaries which are hoisted to the parent scope on exit.
+template <class Emitter> class ExprScope final : public LocalScope<Emitter> {
+public:
+ ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
+
+ void addExtended(const Scope::Local &Local) override {
+ this->Parent->addLocal(Local);
+ }
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/ByteCodeGenError.cpp b/lib/AST/Interp/ByteCodeGenError.cpp
new file mode 100644
index 000000000000..5fd3d77c3842
--- /dev/null
+++ b/lib/AST/Interp/ByteCodeGenError.cpp
@@ -0,0 +1,14 @@
+//===--- ByteCodeGenError.h - Byte code generation error --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ByteCodeGenError.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+char ByteCodeGenError::ID;
diff --git a/lib/AST/Interp/ByteCodeGenError.h b/lib/AST/Interp/ByteCodeGenError.h
new file mode 100644
index 000000000000..a4fa4917705d
--- /dev/null
+++ b/lib/AST/Interp/ByteCodeGenError.h
@@ -0,0 +1,46 @@
+//===--- ByteCodeGenError.h - Byte code generation error ----------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_BYTECODEGENERROR_H
+#define LLVM_CLANG_AST_INTERP_BYTECODEGENERROR_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+namespace interp {
+
+/// Error thrown by the compiler.
+struct ByteCodeGenError : public llvm::ErrorInfo<ByteCodeGenError> {
+public:
+ ByteCodeGenError(SourceLocation Loc) : Loc(Loc) {}
+ ByteCodeGenError(const Stmt *S) : ByteCodeGenError(S->getBeginLoc()) {}
+ ByteCodeGenError(const Decl *D) : ByteCodeGenError(D->getBeginLoc()) {}
+
+ void log(raw_ostream &OS) const override { OS << "unimplemented feature"; }
+
+ const SourceLocation &getLoc() const { return Loc; }
+
+ static char ID;
+
+private:
+ // Start of the item where the error occurred.
+ SourceLocation Loc;
+
+ // Users are not expected to use error_code.
+ std::error_code convertToErrorCode() const override {
+ return llvm::inconvertibleErrorCode();
+ }
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/ByteCodeStmtGen.cpp b/lib/AST/Interp/ByteCodeStmtGen.cpp
new file mode 100644
index 000000000000..c71301598bde
--- /dev/null
+++ b/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -0,0 +1,265 @@
+//===--- ByteCodeStmtGen.cpp - Code generator for expressions ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ByteCodeStmtGen.h"
+#include "ByteCodeEmitter.h"
+#include "ByteCodeGenError.h"
+#include "Context.h"
+#include "Function.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "State.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+template <typename T> using Expected = llvm::Expected<T>;
+template <typename T> using Optional = llvm::Optional<T>;
+
+namespace clang {
+namespace interp {
+
+/// Scope managing label targets.
+template <class Emitter> class LabelScope {
+public:
+ virtual ~LabelScope() { }
+
+protected:
+ LabelScope(ByteCodeStmtGen<Emitter> *Ctx) : Ctx(Ctx) {}
+ /// ByteCodeStmtGen instance.
+ ByteCodeStmtGen<Emitter> *Ctx;
+};
+
+/// Sets the context for break/continue statements.
+template <class Emitter> class LoopScope final : public LabelScope<Emitter> {
+public:
+ using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
+ using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
+
+ LoopScope(ByteCodeStmtGen<Emitter> *Ctx, LabelTy BreakLabel,
+ LabelTy ContinueLabel)
+ : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
+ OldContinueLabel(Ctx->ContinueLabel) {
+ this->Ctx->BreakLabel = BreakLabel;
+ this->Ctx->ContinueLabel = ContinueLabel;
+ }
+
+ ~LoopScope() {
+ this->Ctx->BreakLabel = OldBreakLabel;
+ this->Ctx->ContinueLabel = OldContinueLabel;
+ }
+
+private:
+ OptLabelTy OldBreakLabel;
+ OptLabelTy OldContinueLabel;
+};
+
+// Sets the context for a switch scope, mapping labels.
+template <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
+public:
+ using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
+ using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
+ using CaseMap = typename ByteCodeStmtGen<Emitter>::CaseMap;
+
+ SwitchScope(ByteCodeStmtGen<Emitter> *Ctx, CaseMap &&CaseLabels,
+ LabelTy BreakLabel, OptLabelTy DefaultLabel)
+ : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
+ OldDefaultLabel(this->Ctx->DefaultLabel),
+ OldCaseLabels(std::move(this->Ctx->CaseLabels)) {
+ this->Ctx->BreakLabel = BreakLabel;
+ this->Ctx->DefaultLabel = DefaultLabel;
+ this->Ctx->CaseLabels = std::move(CaseLabels);
+ }
+
+ ~SwitchScope() {
+ this->Ctx->BreakLabel = OldBreakLabel;
+ this->Ctx->DefaultLabel = OldDefaultLabel;
+ this->Ctx->CaseLabels = std::move(OldCaseLabels);
+ }
+
+private:
+ OptLabelTy OldBreakLabel;
+ OptLabelTy OldDefaultLabel;
+ CaseMap OldCaseLabels;
+};
+
+} // namespace interp
+} // namespace clang
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
+ // Classify the return type.
+ ReturnType = this->classify(F->getReturnType());
+
+ // Set up fields and context if a constructor.
+ if (auto *MD = dyn_cast<CXXMethodDecl>(F))
+ return this->bail(MD);
+
+ if (auto *Body = F->getBody())
+ if (!visitStmt(Body))
+ return false;
+
+ // Emit a guard return to protect against a code path missing one.
+ if (F->getReturnType()->isVoidType())
+ return this->emitRetVoid(SourceInfo{});
+ else
+ return this->emitNoRet(SourceInfo{});
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) {
+ switch (S->getStmtClass()) {
+ case Stmt::CompoundStmtClass:
+ return visitCompoundStmt(cast<CompoundStmt>(S));
+ case Stmt::DeclStmtClass:
+ return visitDeclStmt(cast<DeclStmt>(S));
+ case Stmt::ReturnStmtClass:
+ return visitReturnStmt(cast<ReturnStmt>(S));
+ case Stmt::IfStmtClass:
+ return visitIfStmt(cast<IfStmt>(S));
+ case Stmt::NullStmtClass:
+ return true;
+ default: {
+ if (auto *Exp = dyn_cast<Expr>(S))
+ return this->discard(Exp);
+ return this->bail(S);
+ }
+ }
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitCompoundStmt(
+ const CompoundStmt *CompoundStmt) {
+ BlockScope<Emitter> Scope(this);
+ for (auto *InnerStmt : CompoundStmt->body())
+ if (!visitStmt(InnerStmt))
+ return false;
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
+ for (auto *D : DS->decls()) {
+ // Variable declarator.
+ if (auto *VD = dyn_cast<VarDecl>(D)) {
+ if (!visitVarDecl(VD))
+ return false;
+ continue;
+ }
+
+ // Decomposition declarator.
+ if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
+ return this->bail(DD);
+ }
+ }
+
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
+ if (const Expr *RE = RS->getRetValue()) {
+ ExprScope<Emitter> RetScope(this);
+ if (ReturnType) {
+ // Primitive types are simply returned.
+ if (!this->visit(RE))
+ return false;
+ this->emitCleanup();
+ return this->emitRet(*ReturnType, RS);
+ } else {
+ // RVO - construct the value in the return location.
+ auto ReturnLocation = [this, RE] { return this->emitGetParamPtr(0, RE); };
+ if (!this->visitInitializer(RE, ReturnLocation))
+ return false;
+ this->emitCleanup();
+ return this->emitRetVoid(RS);
+ }
+ } else {
+ this->emitCleanup();
+ if (!this->emitRetVoid(RS))
+ return false;
+ return true;
+ }
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) {
+ BlockScope<Emitter> IfScope(this);
+ if (auto *CondInit = IS->getInit())
+ if (!visitStmt(IS->getInit()))
+ return false;
+
+ if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt())
+ if (!visitDeclStmt(CondDecl))
+ return false;
+
+ if (!this->visitBool(IS->getCond()))
+ return false;
+
+ if (const Stmt *Else = IS->getElse()) {
+ LabelTy LabelElse = this->getLabel();
+ LabelTy LabelEnd = this->getLabel();
+ if (!this->jumpFalse(LabelElse))
+ return false;
+ if (!visitStmt(IS->getThen()))
+ return false;
+ if (!this->jump(LabelEnd))
+ return false;
+ this->emitLabel(LabelElse);
+ if (!visitStmt(Else))
+ return false;
+ this->emitLabel(LabelEnd);
+ } else {
+ LabelTy LabelEnd = this->getLabel();
+ if (!this->jumpFalse(LabelEnd))
+ return false;
+ if (!visitStmt(IS->getThen()))
+ return false;
+ this->emitLabel(LabelEnd);
+ }
+
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
+ auto DT = VD->getType();
+
+ if (!VD->hasLocalStorage()) {
+ // No code generation required.
+ return true;
+ }
+
+ // Integers, pointers, primitives.
+ if (Optional<PrimType> T = this->classify(DT)) {
+ auto Off = this->allocateLocalPrimitive(VD, *T, DT.isConstQualified());
+ // Compile the initialiser in its own scope.
+ {
+ ExprScope<Emitter> Scope(this);
+ if (!this->visit(VD->getInit()))
+ return false;
+ }
+ // Set the value.
+ return this->emitSetLocal(*T, Off, VD);
+ } else {
+ // Composite types - allocate storage and initialize it.
+ if (auto Off = this->allocateLocal(VD)) {
+ return this->visitLocalInitializer(VD->getInit(), *Off);
+ } else {
+ return this->bail(VD);
+ }
+ }
+}
+
+namespace clang {
+namespace interp {
+
+template class ByteCodeStmtGen<ByteCodeEmitter>;
+
+} // namespace interp
+} // namespace clang
diff --git a/lib/AST/Interp/ByteCodeStmtGen.h b/lib/AST/Interp/ByteCodeStmtGen.h
new file mode 100644
index 000000000000..d9c0b64ed4b8
--- /dev/null
+++ b/lib/AST/Interp/ByteCodeStmtGen.h
@@ -0,0 +1,89 @@
+//===--- ByteCodeStmtGen.h - Code generator for expressions -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the constexpr bytecode compiler.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_BYTECODESTMTGEN_H
+#define LLVM_CLANG_AST_INTERP_BYTECODESTMTGEN_H
+
+#include "ByteCodeEmitter.h"
+#include "ByteCodeExprGen.h"
+#include "EvalEmitter.h"
+#include "Pointer.h"
+#include "PrimType.h"
+#include "Record.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/StmtVisitor.h"
+#include "llvm/ADT/Optional.h"
+
+namespace clang {
+class QualType;
+
+namespace interp {
+class Function;
+class State;
+
+template <class Emitter> class LoopScope;
+template <class Emitter> class SwitchScope;
+template <class Emitter> class LabelScope;
+
+/// Compilation context for statements.
+template <class Emitter>
+class ByteCodeStmtGen : public ByteCodeExprGen<Emitter> {
+ using LabelTy = typename Emitter::LabelTy;
+ using AddrTy = typename Emitter::AddrTy;
+ using OptLabelTy = llvm::Optional<LabelTy>;
+ using CaseMap = llvm::DenseMap<const SwitchCase *, LabelTy>;
+
+public:
+ template<typename... Tys>
+ ByteCodeStmtGen(Tys&&... Args)
+ : ByteCodeExprGen<Emitter>(std::forward<Tys>(Args)...) {}
+
+protected:
+ bool visitFunc(const FunctionDecl *F) override;
+
+private:
+ friend class LabelScope<Emitter>;
+ friend class LoopScope<Emitter>;
+ friend class SwitchScope<Emitter>;
+
+ // Statement visitors.
+ bool visitStmt(const Stmt *S);
+ bool visitCompoundStmt(const CompoundStmt *S);
+ bool visitDeclStmt(const DeclStmt *DS);
+ bool visitReturnStmt(const ReturnStmt *RS);
+ bool visitIfStmt(const IfStmt *IS);
+
+ /// Compiles a variable declaration.
+ bool visitVarDecl(const VarDecl *VD);
+
+private:
+ /// Type of the expression returned by the function.
+ llvm::Optional<PrimType> ReturnType;
+
+ /// Switch case mapping.
+ CaseMap CaseLabels;
+
+ /// Point to break to.
+ OptLabelTy BreakLabel;
+ /// Point to continue to.
+ OptLabelTy ContinueLabel;
+ /// Default case label.
+ OptLabelTy DefaultLabel;
+};
+
+extern template class ByteCodeExprGen<EvalEmitter>;
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/Context.cpp b/lib/AST/Interp/Context.cpp
new file mode 100644
index 000000000000..4f8f7b96e7c3
--- /dev/null
+++ b/lib/AST/Interp/Context.cpp
@@ -0,0 +1,148 @@
+//===--- Context.cpp - Context for the constexpr VM -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Context.h"
+#include "ByteCodeEmitter.h"
+#include "ByteCodeExprGen.h"
+#include "ByteCodeStmtGen.h"
+#include "EvalEmitter.h"
+#include "Interp.h"
+#include "InterpFrame.h"
+#include "InterpStack.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "clang/AST/Expr.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+Context::Context(ASTContext &Ctx)
+ : Ctx(Ctx), ForceInterp(getLangOpts().ForceNewConstInterp),
+ P(new Program(*this)) {}
+
+Context::~Context() {}
+
+InterpResult Context::isPotentialConstantExpr(State &Parent,
+ const FunctionDecl *FD) {
+ Function *Func = P->getFunction(FD);
+ if (!Func) {
+ if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD)) {
+ Func = *R;
+ } else if (ForceInterp) {
+ handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) {
+ Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed);
+ });
+ return InterpResult::Fail;
+ } else {
+ consumeError(R.takeError());
+ return InterpResult::Bail;
+ }
+ }
+
+ if (!Func->isConstexpr())
+ return InterpResult::Fail;
+
+ APValue Dummy;
+ return Run(Parent, Func, Dummy);
+}
+
+InterpResult Context::evaluateAsRValue(State &Parent, const Expr *E,
+ APValue &Result) {
+ ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
+ return Check(Parent, C.interpretExpr(E));
+}
+
+InterpResult Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
+ APValue &Result) {
+ ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
+ return Check(Parent, C.interpretDecl(VD));
+}
+
+const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }
+
+llvm::Optional<PrimType> Context::classify(QualType T) {
+ if (T->isReferenceType() || T->isPointerType()) {
+ return PT_Ptr;
+ }
+
+ if (T->isBooleanType())
+ return PT_Bool;
+
+ if (T->isSignedIntegerOrEnumerationType()) {
+ switch (Ctx.getIntWidth(T)) {
+ case 64:
+ return PT_Sint64;
+ case 32:
+ return PT_Sint32;
+ case 16:
+ return PT_Sint16;
+ case 8:
+ return PT_Sint8;
+ default:
+ return {};
+ }
+ }
+
+ if (T->isUnsignedIntegerOrEnumerationType()) {
+ switch (Ctx.getIntWidth(T)) {
+ case 64:
+ return PT_Uint64;
+ case 32:
+ return PT_Uint32;
+ case 16:
+ return PT_Uint16;
+ case 8:
+ return PT_Uint8;
+ default:
+ return {};
+ }
+ }
+
+ if (T->isNullPtrType())
+ return PT_Ptr;
+
+ if (auto *AT = dyn_cast<AtomicType>(T))
+ return classify(AT->getValueType());
+
+ return {};
+}
+
+unsigned Context::getCharBit() const {
+ return Ctx.getTargetInfo().getCharWidth();
+}
+
+InterpResult Context::Run(State &Parent, Function *Func, APValue &Result) {
+ InterpResult Flag;
+ {
+ InterpState State(Parent, *P, Stk, *this);
+ State.Current = new InterpFrame(State, Func, nullptr, {}, {});
+ if (Interpret(State, Result)) {
+ Flag = InterpResult::Success;
+ } else {
+ Flag = InterpResult::Fail;
+ }
+ }
+
+ if (Flag != InterpResult::Success)
+ Stk.clear();
+ return Flag;
+}
+
+InterpResult Context::Check(State &Parent, llvm::Expected<bool> &&R) {
+ if (R) {
+ return *R ? InterpResult::Success : InterpResult::Fail;
+ } else if (ForceInterp) {
+ handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) {
+ Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed);
+ });
+ return InterpResult::Fail;
+ } else {
+ consumeError(R.takeError());
+ return InterpResult::Bail;
+ }
+}
diff --git a/lib/AST/Interp/Context.h b/lib/AST/Interp/Context.h
new file mode 100644
index 000000000000..96368b6e5f02
--- /dev/null
+++ b/lib/AST/Interp/Context.h
@@ -0,0 +1,100 @@
+//===--- Context.h - Context for the constexpr VM ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the constexpr execution context.
+//
+// The execution context manages cached bytecode and the global context.
+// It invokes the compiler and interpreter, propagating errors.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_CONTEXT_H
+#define LLVM_CLANG_AST_INTERP_CONTEXT_H
+
+#include "Context.h"
+#include "InterpStack.h"
+#include "clang/AST/APValue.h"
+#include "llvm/ADT/PointerIntPair.h"
+
+namespace clang {
+class ASTContext;
+class LangOptions;
+class Stmt;
+class FunctionDecl;
+class VarDecl;
+
+namespace interp {
+class Function;
+class Program;
+class State;
+enum PrimType : unsigned;
+
+/// Wrapper around interpreter termination results.
+enum class InterpResult {
+ /// Interpreter successfully computed a value.
+ Success,
+ /// Interpreter encountered an error and quit.
+ Fail,
+ /// Interpreter encountered an unimplemented feature, AST fallback.
+ Bail,
+};
+
+/// Holds all information required to evaluate constexpr code in a module.
+class Context {
+public:
+ /// Initialises the constexpr VM.
+ Context(ASTContext &Ctx);
+
+ /// Cleans up the constexpr VM.
+ ~Context();
+
+ /// Checks if a function is a potential constant expression.
+ InterpResult isPotentialConstantExpr(State &Parent,
+ const FunctionDecl *FnDecl);
+
+ /// Evaluates a toplevel expression as an rvalue.
+ InterpResult evaluateAsRValue(State &Parent, const Expr *E, APValue &Result);
+
+ /// Evaluates a toplevel initializer.
+ InterpResult evaluateAsInitializer(State &Parent, const VarDecl *VD,
+ APValue &Result);
+
+ /// Returns the AST context.
+ ASTContext &getASTContext() const { return Ctx; }
+ /// Returns the language options.
+ const LangOptions &getLangOpts() const;
+ /// Returns the interpreter stack.
+ InterpStack &getStack() { return Stk; }
+ /// Returns CHAR_BIT.
+ unsigned getCharBit() const;
+
+ /// Classifies an expression.
+ llvm::Optional<PrimType> classify(QualType T);
+
+private:
+ /// Runs a function.
+ InterpResult Run(State &Parent, Function *Func, APValue &Result);
+
+ /// Checks a result fromt the interpreter.
+ InterpResult Check(State &Parent, llvm::Expected<bool> &&R);
+
+private:
+ /// Current compilation context.
+ ASTContext &Ctx;
+ /// Flag to indicate if the use of the interpreter is mandatory.
+ bool ForceInterp;
+ /// Interpreter stack, shared across invocations.
+ InterpStack Stk;
+ /// Constexpr program.
+ std::unique_ptr<Program> P;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/Descriptor.cpp b/lib/AST/Interp/Descriptor.cpp
new file mode 100644
index 000000000000..5c1a8a9cf306
--- /dev/null
+++ b/lib/AST/Interp/Descriptor.cpp
@@ -0,0 +1,292 @@
+//===--- Descriptor.cpp - Types for the constexpr VM ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Descriptor.h"
+#include "Pointer.h"
+#include "PrimType.h"
+#include "Record.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+template <typename T>
+static void ctorTy(Block *, char *Ptr, bool, bool, bool, Descriptor *) {
+ new (Ptr) T();
+}
+
+template <typename T> static void dtorTy(Block *, char *Ptr, Descriptor *) {
+ reinterpret_cast<T *>(Ptr)->~T();
+}
+
+template <typename T>
+static void moveTy(Block *, char *Src, char *Dst, Descriptor *) {
+ auto *SrcPtr = reinterpret_cast<T *>(Src);
+ auto *DstPtr = reinterpret_cast<T *>(Dst);
+ new (DstPtr) T(std::move(*SrcPtr));
+}
+
+template <typename T>
+static void ctorArrayTy(Block *, char *Ptr, bool, bool, bool, Descriptor *D) {
+ for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
+ new (&reinterpret_cast<T *>(Ptr)[I]) T();
+ }
+}
+
+template <typename T>
+static void dtorArrayTy(Block *, char *Ptr, Descriptor *D) {
+ for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
+ reinterpret_cast<T *>(Ptr)[I].~T();
+ }
+}
+
+template <typename T>
+static void moveArrayTy(Block *, char *Src, char *Dst, Descriptor *D) {
+ for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
+ auto *SrcPtr = &reinterpret_cast<T *>(Src)[I];
+ auto *DstPtr = &reinterpret_cast<T *>(Dst)[I];
+ new (DstPtr) T(std::move(*SrcPtr));
+ }
+}
+
+static void ctorArrayDesc(Block *B, char *Ptr, bool IsConst, bool IsMutable,
+ bool IsActive, Descriptor *D) {
+ const unsigned NumElems = D->getNumElems();
+ const unsigned ElemSize =
+ D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
+
+ unsigned ElemOffset = 0;
+ for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
+ auto *ElemPtr = Ptr + ElemOffset;
+ auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
+ auto *ElemLoc = reinterpret_cast<char *>(Desc + 1);
+ auto *SD = D->ElemDesc;
+
+ Desc->Offset = ElemOffset + sizeof(InlineDescriptor);
+ Desc->Desc = SD;
+ Desc->IsInitialized = true;
+ Desc->IsBase = false;
+ Desc->IsActive = IsActive;
+ Desc->IsConst = IsConst || D->IsConst;
+ Desc->IsMutable = IsMutable || D->IsMutable;
+ if (auto Fn = D->ElemDesc->CtorFn)
+ Fn(B, ElemLoc, Desc->IsConst, Desc->IsMutable, IsActive, D->ElemDesc);
+ }
+}
+
+static void dtorArrayDesc(Block *B, char *Ptr, Descriptor *D) {
+ const unsigned NumElems = D->getNumElems();
+ const unsigned ElemSize =
+ D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
+
+ unsigned ElemOffset = 0;
+ for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
+ auto *ElemPtr = Ptr + ElemOffset;
+ auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
+ auto *ElemLoc = reinterpret_cast<char *>(Desc + 1);
+ if (auto Fn = D->ElemDesc->DtorFn)
+ Fn(B, ElemLoc, D->ElemDesc);
+ }
+}
+
+static void moveArrayDesc(Block *B, char *Src, char *Dst, Descriptor *D) {
+ const unsigned NumElems = D->getNumElems();
+ const unsigned ElemSize =
+ D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
+
+ unsigned ElemOffset = 0;
+ for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
+ auto *SrcPtr = Src + ElemOffset;
+ auto *DstPtr = Dst + ElemOffset;
+
+ auto *SrcDesc = reinterpret_cast<InlineDescriptor *>(SrcPtr);
+ auto *SrcElemLoc = reinterpret_cast<char *>(SrcDesc + 1);
+ auto *DstDesc = reinterpret_cast<InlineDescriptor *>(DstPtr);
+ auto *DstElemLoc = reinterpret_cast<char *>(DstDesc + 1);
+
+ *DstDesc = *SrcDesc;
+ if (auto Fn = D->ElemDesc->MoveFn)
+ Fn(B, SrcElemLoc, DstElemLoc, D->ElemDesc);
+ }
+}
+
+static void ctorRecord(Block *B, char *Ptr, bool IsConst, bool IsMutable,
+ bool IsActive, Descriptor *D) {
+ const bool IsUnion = D->ElemRecord->isUnion();
+ auto CtorSub = [=](unsigned SubOff, Descriptor *F, bool IsBase) {
+ auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + SubOff) - 1;
+ Desc->Offset = SubOff;
+ Desc->Desc = F;
+ Desc->IsInitialized = (B->isStatic() || F->IsArray) && !IsBase;
+ Desc->IsBase = IsBase;
+ Desc->IsActive = IsActive && !IsUnion;
+ Desc->IsConst = IsConst || F->IsConst;
+ Desc->IsMutable = IsMutable || F->IsMutable;
+ if (auto Fn = F->CtorFn)
+ Fn(B, Ptr + SubOff, Desc->IsConst, Desc->IsMutable, Desc->IsActive, F);
+ };
+ for (const auto &B : D->ElemRecord->bases())
+ CtorSub(B.Offset, B.Desc, /*isBase=*/true);
+ for (const auto &F : D->ElemRecord->fields())
+ CtorSub(F.Offset, F.Desc, /*isBase=*/false);
+ for (const auto &V : D->ElemRecord->virtual_bases())
+ CtorSub(V.Offset, V.Desc, /*isBase=*/true);
+}
+
+static void dtorRecord(Block *B, char *Ptr, Descriptor *D) {
+ auto DtorSub = [=](unsigned SubOff, Descriptor *F) {
+ if (auto Fn = F->DtorFn)
+ Fn(B, Ptr + SubOff, F);
+ };
+ for (const auto &F : D->ElemRecord->bases())
+ DtorSub(F.Offset, F.Desc);
+ for (const auto &F : D->ElemRecord->fields())
+ DtorSub(F.Offset, F.Desc);
+ for (const auto &F : D->ElemRecord->virtual_bases())
+ DtorSub(F.Offset, F.Desc);
+}
+
+static void moveRecord(Block *B, char *Src, char *Dst, Descriptor *D) {
+ for (const auto &F : D->ElemRecord->fields()) {
+ auto FieldOff = F.Offset;
+ auto FieldDesc = F.Desc;
+
+ *(reinterpret_cast<Descriptor **>(Dst + FieldOff) - 1) = FieldDesc;
+ if (auto Fn = FieldDesc->MoveFn)
+ Fn(B, Src + FieldOff, Dst + FieldOff, FieldDesc);
+ }
+}
+
+static BlockCtorFn getCtorPrim(PrimType Type) {
+ COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);
+}
+
+static BlockDtorFn getDtorPrim(PrimType Type) {
+ COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr);
+}
+
+static BlockMoveFn getMovePrim(PrimType Type) {
+ COMPOSITE_TYPE_SWITCH(Type, return moveTy<T>, return nullptr);
+}
+
+static BlockCtorFn getCtorArrayPrim(PrimType Type) {
+ COMPOSITE_TYPE_SWITCH(Type, return ctorArrayTy<T>, return nullptr);
+}
+
+static BlockDtorFn getDtorArrayPrim(PrimType Type) {
+ COMPOSITE_TYPE_SWITCH(Type, return dtorArrayTy<T>, return nullptr);
+}
+
+static BlockMoveFn getMoveArrayPrim(PrimType Type) {
+ COMPOSITE_TYPE_SWITCH(Type, return moveArrayTy<T>, return nullptr);
+}
+
+Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsConst,
+ bool IsTemporary, bool IsMutable)
+ : Source(D), ElemSize(primSize(Type)), Size(ElemSize), AllocSize(Size),
+ IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
+ CtorFn(getCtorPrim(Type)), DtorFn(getDtorPrim(Type)),
+ MoveFn(getMovePrim(Type)) {
+ assert(Source && "Missing source");
+}
+
+Descriptor::Descriptor(const DeclTy &D, PrimType Type, size_t NumElems,
+ bool IsConst, bool IsTemporary, bool IsMutable)
+ : Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),
+ AllocSize(align(Size) + sizeof(InitMap *)), IsConst(IsConst),
+ IsMutable(IsMutable), IsTemporary(IsTemporary), IsArray(true),
+ CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)),
+ MoveFn(getMoveArrayPrim(Type)) {
+ assert(Source && "Missing source");
+}
+
+Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsTemporary,
+ UnknownSize)
+ : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),
+ AllocSize(alignof(void *)), IsConst(true), IsMutable(false),
+ IsTemporary(IsTemporary), IsArray(true), CtorFn(getCtorArrayPrim(Type)),
+ DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {
+ assert(Source && "Missing source");
+}
+
+Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, unsigned NumElems,
+ bool IsConst, bool IsTemporary, bool IsMutable)
+ : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
+ Size(ElemSize * NumElems),
+ AllocSize(std::max<size_t>(alignof(void *), Size)), ElemDesc(Elem),
+ IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
+ IsArray(true), CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc),
+ MoveFn(moveArrayDesc) {
+ assert(Source && "Missing source");
+}
+
+Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary,
+ UnknownSize)
+ : Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
+ Size(UnknownSizeMark), AllocSize(alignof(void *)), ElemDesc(Elem),
+ IsConst(true), IsMutable(false), IsTemporary(IsTemporary), IsArray(true),
+ CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {
+ assert(Source && "Missing source");
+}
+
+Descriptor::Descriptor(const DeclTy &D, Record *R, bool IsConst,
+ bool IsTemporary, bool IsMutable)
+ : Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),
+ Size(ElemSize), AllocSize(Size), ElemRecord(R), IsConst(IsConst),
+ IsMutable(IsMutable), IsTemporary(IsTemporary), CtorFn(ctorRecord),
+ DtorFn(dtorRecord), MoveFn(moveRecord) {
+ assert(Source && "Missing source");
+}
+
+QualType Descriptor::getType() const {
+ if (auto *E = asExpr())
+ return E->getType();
+ if (auto *D = asValueDecl())
+ return D->getType();
+ llvm_unreachable("Invalid descriptor type");
+}
+
+SourceLocation Descriptor::getLocation() const {
+ if (auto *D = Source.dyn_cast<const Decl *>())
+ return D->getLocation();
+ if (auto *E = Source.dyn_cast<const Expr *>())
+ return E->getExprLoc();
+ llvm_unreachable("Invalid descriptor type");
+}
+
+InitMap::InitMap(unsigned N) : UninitFields(N) {
+ for (unsigned I = 0; I < N / PER_FIELD; ++I) {
+ data()[I] = 0;
+ }
+}
+
+InitMap::T *InitMap::data() {
+ auto *Start = reinterpret_cast<char *>(this) + align(sizeof(InitMap));
+ return reinterpret_cast<T *>(Start);
+}
+
+bool InitMap::initialize(unsigned I) {
+ unsigned Bucket = I / PER_FIELD;
+ unsigned Mask = 1ull << static_cast<uint64_t>(I % PER_FIELD);
+ if (!(data()[Bucket] & Mask)) {
+ data()[Bucket] |= Mask;
+ UninitFields -= 1;
+ }
+ return UninitFields == 0;
+}
+
+bool InitMap::isInitialized(unsigned I) {
+ unsigned Bucket = I / PER_FIELD;
+ unsigned Mask = 1ull << static_cast<uint64_t>(I % PER_FIELD);
+ return data()[Bucket] & Mask;
+}
+
+InitMap *InitMap::allocate(unsigned N) {
+ const size_t NumFields = ((N + PER_FIELD - 1) / PER_FIELD);
+ const size_t Size = align(sizeof(InitMap)) + NumFields * PER_FIELD;
+ return new (malloc(Size)) InitMap(N);
+}
diff --git a/lib/AST/Interp/Descriptor.h b/lib/AST/Interp/Descriptor.h
new file mode 100644
index 000000000000..b260b7600974
--- /dev/null
+++ b/lib/AST/Interp/Descriptor.h
@@ -0,0 +1,220 @@
+//===--- Descriptor.h - Types for the constexpr VM --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines descriptors which characterise allocations.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_DESCRIPTOR_H
+#define LLVM_CLANG_AST_INTERP_DESCRIPTOR_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+
+namespace clang {
+namespace interp {
+class Block;
+class Record;
+struct Descriptor;
+enum PrimType : unsigned;
+
+using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>;
+
+/// Invoked whenever a block is created. The constructor method fills in the
+/// inline descriptors of all fields and array elements. It also initializes
+/// all the fields which contain non-trivial types.
+using BlockCtorFn = void (*)(Block *Storage, char *FieldPtr, bool IsConst,
+ bool IsMutable, bool IsActive,
+ Descriptor *FieldDesc);
+
+/// Invoked when a block is destroyed. Invokes the destructors of all
+/// non-trivial nested fields of arrays and records.
+using BlockDtorFn = void (*)(Block *Storage, char *FieldPtr,
+ Descriptor *FieldDesc);
+
+/// Invoked when a block with pointers referencing it goes out of scope. Such
+/// blocks are persisted: the move function copies all inline descriptors and
+/// non-trivial fields, as existing pointers might need to reference those
+/// descriptors. Data is not copied since it cannot be legally read.
+using BlockMoveFn = void (*)(Block *Storage, char *SrcFieldPtr,
+ char *DstFieldPtr, Descriptor *FieldDesc);
+
+/// Object size as used by the interpreter.
+using InterpSize = unsigned;
+
+/// Describes a memory block created by an allocation site.
+struct Descriptor {
+private:
+ /// Original declaration, used to emit the error message.
+ const DeclTy Source;
+ /// Size of an element, in host bytes.
+ const InterpSize ElemSize;
+ /// Size of the storage, in host bytes.
+ const InterpSize Size;
+ /// Size of the allocation (storage + metadata), in host bytes.
+ const InterpSize AllocSize;
+
+ /// Value to denote arrays of unknown size.
+ static constexpr unsigned UnknownSizeMark = (unsigned)-1;
+
+public:
+ /// Token to denote structures of unknown size.
+ struct UnknownSize {};
+
+ /// Pointer to the record, if block contains records.
+ Record *const ElemRecord = nullptr;
+ /// Descriptor of the array element.
+ Descriptor *const ElemDesc = nullptr;
+ /// Flag indicating if the block is mutable.
+ const bool IsConst = false;
+ /// Flag indicating if a field is mutable.
+ const bool IsMutable = false;
+ /// Flag indicating if the block is a temporary.
+ const bool IsTemporary = false;
+ /// Flag indicating if the block is an array.
+ const bool IsArray = false;
+
+ /// Storage management methods.
+ const BlockCtorFn CtorFn = nullptr;
+ const BlockDtorFn DtorFn = nullptr;
+ const BlockMoveFn MoveFn = nullptr;
+
+ /// Allocates a descriptor for a primitive.
+ Descriptor(const DeclTy &D, PrimType Type, bool IsConst, bool IsTemporary,
+ bool IsMutable);
+
+ /// Allocates a descriptor for an array of primitives.
+ Descriptor(const DeclTy &D, PrimType Type, size_t NumElems, bool IsConst,
+ bool IsTemporary, bool IsMutable);
+
+ /// Allocates a descriptor for an array of primitives of unknown size.
+ Descriptor(const DeclTy &D, PrimType Type, bool IsTemporary, UnknownSize);
+
+ /// Allocates a descriptor for an array of composites.
+ Descriptor(const DeclTy &D, Descriptor *Elem, unsigned NumElems, bool IsConst,
+ bool IsTemporary, bool IsMutable);
+
+ /// Allocates a descriptor for an array of composites of unknown size.
+ Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary, UnknownSize);
+
+ /// Allocates a descriptor for a record.
+ Descriptor(const DeclTy &D, Record *R, bool IsConst, bool IsTemporary,
+ bool IsMutable);
+
+ QualType getType() const;
+ SourceLocation getLocation() const;
+
+ const Decl *asDecl() const { return Source.dyn_cast<const Decl *>(); }
+ const Expr *asExpr() const { return Source.dyn_cast<const Expr *>(); }
+
+ const ValueDecl *asValueDecl() const {
+ return dyn_cast_or_null<ValueDecl>(asDecl());
+ }
+
+ const FieldDecl *asFieldDecl() const {
+ return dyn_cast_or_null<FieldDecl>(asDecl());
+ }
+
+ const RecordDecl *asRecordDecl() const {
+ return dyn_cast_or_null<RecordDecl>(asDecl());
+ }
+
+ /// Returns the size of the object without metadata.
+ unsigned getSize() const {
+ assert(!isUnknownSizeArray() && "Array of unknown size");
+ return Size;
+ }
+
+ /// Returns the allocated size, including metadata.
+ unsigned getAllocSize() const { return AllocSize; }
+ /// returns the size of an element when the structure is viewed as an array.
+ unsigned getElemSize() const { return ElemSize; }
+
+ /// Returns the number of elements stored in the block.
+ unsigned getNumElems() const {
+ return Size == UnknownSizeMark ? 0 : (getSize() / getElemSize());
+ }
+
+ /// Checks if the descriptor is of an array of primitives.
+ bool isPrimitiveArray() const { return IsArray && !ElemDesc; }
+ /// Checks if the descriptor is of an array of zero size.
+ bool isZeroSizeArray() const { return Size == 0; }
+ /// Checks if the descriptor is of an array of unknown size.
+ bool isUnknownSizeArray() const { return Size == UnknownSizeMark; }
+
+ /// Checks if the descriptor is of a primitive.
+ bool isPrimitive() const { return !IsArray && !ElemRecord; }
+
+ /// Checks if the descriptor is of an array.
+ bool isArray() const { return IsArray; }
+};
+
+/// Inline descriptor embedded in structures and arrays.
+///
+/// Such descriptors precede all composite array elements and structure fields.
+/// If the base of a pointer is not zero, the base points to the end of this
+/// structure. The offset field is used to traverse the pointer chain up
+/// to the root structure which allocated the object.
+struct InlineDescriptor {
+ /// Offset inside the structure/array.
+ unsigned Offset;
+
+ /// Flag indicating if the storage is constant or not.
+ /// Relevant for primitive fields.
+ unsigned IsConst : 1;
+ /// For primitive fields, it indicates if the field was initialized.
+ /// Primitive fields in static storage are always initialized.
+ /// Arrays are always initialized, even though their elements might not be.
+ /// Base classes are initialized after the constructor is invoked.
+ unsigned IsInitialized : 1;
+ /// Flag indicating if the field is an embedded base class.
+ unsigned IsBase : 1;
+ /// Flag indicating if the field is the active member of a union.
+ unsigned IsActive : 1;
+ /// Flag indicating if the field is mutable (if in a record).
+ unsigned IsMutable : 1;
+
+ Descriptor *Desc;
+};
+
+/// Bitfield tracking the initialisation status of elements of primitive arrays.
+/// A pointer to this is embedded at the end of all primitive arrays.
+/// If the map was not yet created and nothing was initialied, the pointer to
+/// this structure is 0. If the object was fully initialized, the pointer is -1.
+struct InitMap {
+private:
+ /// Type packing bits.
+ using T = uint64_t;
+ /// Bits stored in a single field.
+ static constexpr uint64_t PER_FIELD = sizeof(T) * CHAR_BIT;
+
+ /// Initializes the map with no fields set.
+ InitMap(unsigned N);
+
+ /// Returns a pointer to storage.
+ T *data();
+
+public:
+ /// Initializes an element. Returns true when object if fully initialized.
+ bool initialize(unsigned I);
+
+ /// Checks if an element was initialized.
+ bool isInitialized(unsigned I);
+
+ /// Allocates a map holding N elements.
+ static InitMap *allocate(unsigned N);
+
+private:
+ /// Number of fields initialized.
+ unsigned UninitFields;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/Disasm.cpp b/lib/AST/Interp/Disasm.cpp
new file mode 100644
index 000000000000..e77a825eb1f2
--- /dev/null
+++ b/lib/AST/Interp/Disasm.cpp
@@ -0,0 +1,69 @@
+//===--- Disasm.cpp - Disassembler for bytecode functions -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Dump method for Function which disassembles the bytecode.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Function.h"
+#include "Opcode.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "clang/AST/DeclCXX.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }
+
+LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {
+ if (F) {
+ if (auto *Cons = dyn_cast<CXXConstructorDecl>(F)) {
+ const std::string &Name = Cons->getParent()->getNameAsString();
+ OS << Name << "::" << Name << ":\n";
+ } else {
+ OS << F->getNameAsString() << ":\n";
+ }
+ } else {
+ OS << "<<expr>>\n";
+ }
+
+ OS << "frame size: " << getFrameSize() << "\n";
+ OS << "arg size: " << getArgSize() << "\n";
+ OS << "rvo: " << hasRVO() << "\n";
+
+ auto PrintName = [&OS](const char *Name) {
+ OS << Name;
+ for (long I = 0, N = strlen(Name); I < 30 - N; ++I) {
+ OS << ' ';
+ }
+ };
+
+ for (CodePtr Start = getCodeBegin(), PC = Start; PC != getCodeEnd();) {
+ size_t Addr = PC - Start;
+ auto Op = PC.read<Opcode>();
+ OS << llvm::format("%8d", Addr) << " ";
+ switch (Op) {
+#define GET_DISASM
+#include "Opcodes.inc"
+#undef GET_DISASM
+ }
+ }
+}
+
+LLVM_DUMP_METHOD void Program::dump() const { dump(llvm::errs()); }
+
+LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
+ for (auto &Func : Funcs) {
+ Func.second->dump();
+ }
+ for (auto &Anon : AnonFuncs) {
+ Anon->dump();
+ }
+}
diff --git a/lib/AST/Interp/EvalEmitter.cpp b/lib/AST/Interp/EvalEmitter.cpp
new file mode 100644
index 000000000000..22e8695b9211
--- /dev/null
+++ b/lib/AST/Interp/EvalEmitter.cpp
@@ -0,0 +1,253 @@
+//===--- EvalEmitter.cpp - Instruction emitter for the VM -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "EvalEmitter.h"
+#include "Context.h"
+#include "Interp.h"
+#include "Opcode.h"
+#include "Program.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+using APSInt = llvm::APSInt;
+template <typename T> using Expected = llvm::Expected<T>;
+
+EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent,
+ InterpStack &Stk, APValue &Result)
+ : Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), Result(Result) {
+ // Create a dummy frame for the interpreter which does not have locals.
+ S.Current = new InterpFrame(S, nullptr, nullptr, CodePtr(), Pointer());
+}
+
+llvm::Expected<bool> EvalEmitter::interpretExpr(const Expr *E) {
+ if (this->visitExpr(E))
+ return true;
+ if (BailLocation)
+ return llvm::make_error<ByteCodeGenError>(*BailLocation);
+ return false;
+}
+
+llvm::Expected<bool> EvalEmitter::interpretDecl(const VarDecl *VD) {
+ if (this->visitDecl(VD))
+ return true;
+ if (BailLocation)
+ return llvm::make_error<ByteCodeGenError>(*BailLocation);
+ return false;
+}
+
+void EvalEmitter::emitLabel(LabelTy Label) {
+ CurrentLabel = Label;
+}
+
+EvalEmitter::LabelTy EvalEmitter::getLabel() { return NextLabel++; }
+
+Scope::Local EvalEmitter::createLocal(Descriptor *D) {
+ // Allocate memory for a local.
+ auto Memory = std::make_unique<char[]>(sizeof(Block) + D->getAllocSize());
+ auto *B = new (Memory.get()) Block(D, /*isStatic=*/false);
+ B->invokeCtor();
+
+ // Register the local.
+ unsigned Off = Locals.size();
+ Locals.insert({Off, std::move(Memory)});
+ return {Off, D};
+}
+
+bool EvalEmitter::bail(const SourceLocation &Loc) {
+ if (!BailLocation)
+ BailLocation = Loc;
+ return false;
+}
+
+bool EvalEmitter::jumpTrue(const LabelTy &Label) {
+ if (isActive()) {
+ if (S.Stk.pop<bool>())
+ ActiveLabel = Label;
+ }
+ return true;
+}
+
+bool EvalEmitter::jumpFalse(const LabelTy &Label) {
+ if (isActive()) {
+ if (!S.Stk.pop<bool>())
+ ActiveLabel = Label;
+ }
+ return true;
+}
+
+bool EvalEmitter::jump(const LabelTy &Label) {
+ if (isActive())
+ CurrentLabel = ActiveLabel = Label;
+ return true;
+}
+
+bool EvalEmitter::fallthrough(const LabelTy &Label) {
+ if (isActive())
+ ActiveLabel = Label;
+ CurrentLabel = Label;
+ return true;
+}
+
+template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
+ if (!isActive())
+ return true;
+ using T = typename PrimConv<OpType>::T;
+ return ReturnValue<T>(S.Stk.pop<T>(), Result);
+}
+
+bool EvalEmitter::emitRetVoid(const SourceInfo &Info) { return true; }
+
+bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
+ // Method to recursively traverse composites.
+ std::function<bool(QualType, const Pointer &, APValue &)> Composite;
+ Composite = [this, &Composite](QualType Ty, const Pointer &Ptr, APValue &R) {
+ if (auto *AT = Ty->getAs<AtomicType>())
+ Ty = AT->getValueType();
+
+ if (auto *RT = Ty->getAs<RecordType>()) {
+ auto *Record = Ptr.getRecord();
+ assert(Record && "Missing record descriptor");
+
+ bool Ok = true;
+ if (RT->getDecl()->isUnion()) {
+ const FieldDecl *ActiveField = nullptr;
+ APValue Value;
+ for (auto &F : Record->fields()) {
+ const Pointer &FP = Ptr.atField(F.Offset);
+ QualType FieldTy = F.Decl->getType();
+ if (FP.isActive()) {
+ if (llvm::Optional<PrimType> T = Ctx.classify(FieldTy)) {
+ TYPE_SWITCH(*T, Ok &= ReturnValue<T>(FP.deref<T>(), Value));
+ } else {
+ Ok &= Composite(FieldTy, FP, Value);
+ }
+ break;
+ }
+ }
+ R = APValue(ActiveField, Value);
+ } else {
+ unsigned NF = Record->getNumFields();
+ unsigned NB = Record->getNumBases();
+ unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
+
+ R = APValue(APValue::UninitStruct(), NB, NF);
+
+ for (unsigned I = 0; I < NF; ++I) {
+ const Record::Field *FD = Record->getField(I);
+ QualType FieldTy = FD->Decl->getType();
+ const Pointer &FP = Ptr.atField(FD->Offset);
+ APValue &Value = R.getStructField(I);
+
+ if (llvm::Optional<PrimType> T = Ctx.classify(FieldTy)) {
+ TYPE_SWITCH(*T, Ok &= ReturnValue<T>(FP.deref<T>(), Value));
+ } else {
+ Ok &= Composite(FieldTy, FP, Value);
+ }
+ }
+
+ for (unsigned I = 0; I < NB; ++I) {
+ const Record::Base *BD = Record->getBase(I);
+ QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
+ const Pointer &BP = Ptr.atField(BD->Offset);
+ Ok &= Composite(BaseTy, BP, R.getStructBase(I));
+ }
+
+ for (unsigned I = 0; I < NV; ++I) {
+ const Record::Base *VD = Record->getVirtualBase(I);
+ QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
+ const Pointer &VP = Ptr.atField(VD->Offset);
+ Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
+ }
+ }
+ return Ok;
+ }
+ if (auto *AT = Ty->getAsArrayTypeUnsafe()) {
+ const size_t NumElems = Ptr.getNumElems();
+ QualType ElemTy = AT->getElementType();
+ R = APValue(APValue::UninitArray{}, NumElems, NumElems);
+
+ bool Ok = true;
+ for (unsigned I = 0; I < NumElems; ++I) {
+ APValue &Slot = R.getArrayInitializedElt(I);
+ const Pointer &EP = Ptr.atIndex(I);
+ if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) {
+ TYPE_SWITCH(*T, Ok &= ReturnValue<T>(EP.deref<T>(), Slot));
+ } else {
+ Ok &= Composite(ElemTy, EP.narrow(), Slot);
+ }
+ }
+ return Ok;
+ }
+ llvm_unreachable("invalid value to return");
+ };
+
+ // Return the composite type.
+ const auto &Ptr = S.Stk.pop<Pointer>();
+ return Composite(Ptr.getType(), Ptr, Result);
+}
+
+bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) {
+ if (!isActive())
+ return true;
+
+ auto It = Locals.find(I);
+ assert(It != Locals.end() && "Missing local variable");
+ S.Stk.push<Pointer>(reinterpret_cast<Block *>(It->second.get()));
+ return true;
+}
+
+template <PrimType OpType>
+bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) {
+ if (!isActive())
+ return true;
+
+ using T = typename PrimConv<OpType>::T;
+
+ auto It = Locals.find(I);
+ assert(It != Locals.end() && "Missing local variable");
+ auto *B = reinterpret_cast<Block *>(It->second.get());
+ S.Stk.push<T>(*reinterpret_cast<T *>(B + 1));
+ return true;
+}
+
+template <PrimType OpType>
+bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) {
+ if (!isActive())
+ return true;
+
+ using T = typename PrimConv<OpType>::T;
+
+ auto It = Locals.find(I);
+ assert(It != Locals.end() && "Missing local variable");
+ auto *B = reinterpret_cast<Block *>(It->second.get());
+ *reinterpret_cast<T *>(B + 1) = S.Stk.pop<T>();
+ return true;
+}
+
+bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) {
+ if (!isActive())
+ return true;
+
+ for (auto &Local : Descriptors[I]) {
+ auto It = Locals.find(Local.Offset);
+ assert(It != Locals.end() && "Missing local variable");
+ S.deallocate(reinterpret_cast<Block *>(It->second.get()));
+ }
+
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Opcode evaluators
+//===----------------------------------------------------------------------===//
+
+#define GET_EVAL_IMPL
+#include "Opcodes.inc"
+#undef GET_EVAL_IMPL
diff --git a/lib/AST/Interp/EvalEmitter.h b/lib/AST/Interp/EvalEmitter.h
new file mode 100644
index 000000000000..eec2ff8ee753
--- /dev/null
+++ b/lib/AST/Interp/EvalEmitter.h
@@ -0,0 +1,129 @@
+//===--- EvalEmitter.h - Instruction emitter for the VM ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the instruction emitters.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_EVALEMITTER_H
+#define LLVM_CLANG_AST_INTERP_EVALEMITTER_H
+
+#include "ByteCodeGenError.h"
+#include "Context.h"
+#include "InterpStack.h"
+#include "InterpState.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "Source.h"
+#include "llvm/Support/Error.h"
+
+namespace clang {
+class FunctionDecl;
+namespace interp {
+class Context;
+class Function;
+class InterpState;
+class Program;
+class SourceInfo;
+enum Opcode : uint32_t;
+
+/// An emitter which evaluates opcodes as they are emitted.
+class EvalEmitter : public SourceMapper {
+public:
+ using LabelTy = uint32_t;
+ using AddrTy = uintptr_t;
+ using Local = Scope::Local;
+
+ llvm::Expected<bool> interpretExpr(const Expr *E);
+ llvm::Expected<bool> interpretDecl(const VarDecl *VD);
+
+protected:
+ EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk,
+ APValue &Result);
+
+ virtual ~EvalEmitter() {}
+
+ /// Define a label.
+ void emitLabel(LabelTy Label);
+ /// Create a label.
+ LabelTy getLabel();
+
+ /// Methods implemented by the compiler.
+ virtual bool visitExpr(const Expr *E) = 0;
+ virtual bool visitDecl(const VarDecl *VD) = 0;
+
+ bool bail(const Stmt *S) { return bail(S->getBeginLoc()); }
+ bool bail(const Decl *D) { return bail(D->getBeginLoc()); }
+ bool bail(const SourceLocation &Loc);
+
+ /// Emits jumps.
+ bool jumpTrue(const LabelTy &Label);
+ bool jumpFalse(const LabelTy &Label);
+ bool jump(const LabelTy &Label);
+ bool fallthrough(const LabelTy &Label);
+
+ /// Callback for registering a local.
+ Local createLocal(Descriptor *D);
+
+ /// Returns the source location of the current opcode.
+ SourceInfo getSource(Function *F, CodePtr PC) const override {
+ return F ? F->getSource(PC) : CurrentSource;
+ }
+
+ /// Parameter indices.
+ llvm::DenseMap<const ParmVarDecl *, unsigned> Params;
+ /// Local descriptors.
+ llvm::SmallVector<SmallVector<Local, 8>, 2> Descriptors;
+
+private:
+ /// Current compilation context.
+ Context &Ctx;
+ /// Current program.
+ Program &P;
+ /// Callee evaluation state.
+ InterpState S;
+ /// Location to write the result to.
+ APValue &Result;
+
+ /// Temporaries which require storage.
+ llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Locals;
+
+ // The emitter always tracks the current instruction and sets OpPC to a token
+ // value which is mapped to the location of the opcode being evaluated.
+ CodePtr OpPC;
+ /// Location of a failure.
+ llvm::Optional<SourceLocation> BailLocation;
+ /// Location of the current instruction.
+ SourceInfo CurrentSource;
+
+ /// Next label ID to generate - first label is 1.
+ LabelTy NextLabel = 1;
+ /// Label being executed - 0 is the entry label.
+ LabelTy CurrentLabel = 0;
+ /// Active block which should be executed.
+ LabelTy ActiveLabel = 0;
+
+ /// Since expressions can only jump forward, predicated execution is
+ /// used to deal with if-else statements.
+ bool isActive() { return CurrentLabel == ActiveLabel; }
+
+ /// Helper to invoke a method.
+ bool ExecuteCall(Function *F, Pointer &&This, const SourceInfo &Info);
+ /// Helper to emit a diagnostic on a missing method.
+ bool ExecuteNoCall(const FunctionDecl *F, const SourceInfo &Info);
+
+protected:
+#define GET_EVAL_PROTO
+#include "Opcodes.inc"
+#undef GET_EVAL_PROTO
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/Frame.cpp b/lib/AST/Interp/Frame.cpp
new file mode 100644
index 000000000000..16134aa1db36
--- /dev/null
+++ b/lib/AST/Interp/Frame.cpp
@@ -0,0 +1,14 @@
+//===--- Frame.cpp - Call frame for the VM and AST Walker -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Frame.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+Frame::~Frame() {}
diff --git a/lib/AST/Interp/Frame.h b/lib/AST/Interp/Frame.h
new file mode 100644
index 000000000000..b9a0ea9412f8
--- /dev/null
+++ b/lib/AST/Interp/Frame.h
@@ -0,0 +1,45 @@
+//===--- Frame.h - Call frame for the VM and AST Walker ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the base class of interpreter and evaluator stack frames.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_FRAME_H
+#define LLVM_CLANG_AST_INTERP_FRAME_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+class FunctionDecl;
+
+namespace interp {
+
+/// Base class for stack frames, shared between VM and walker.
+class Frame {
+public:
+ virtual ~Frame();
+
+ /// Generates a human-readable description of the call site.
+ virtual void describe(llvm::raw_ostream &OS) = 0;
+
+ /// Returns a pointer to the caller frame.
+ virtual Frame *getCaller() const = 0;
+
+ /// Returns the location of the call site.
+ virtual SourceLocation getCallLocation() const = 0;
+
+ /// Returns the called function's declaration.
+ virtual const FunctionDecl *getCallee() const = 0;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/Function.cpp b/lib/AST/Interp/Function.cpp
new file mode 100644
index 000000000000..0ed13a92aa38
--- /dev/null
+++ b/lib/AST/Interp/Function.cpp
@@ -0,0 +1,48 @@
+//===--- Function.h - Bytecode function for the VM --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Function.h"
+#include "Program.h"
+#include "Opcode.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+Function::Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
+ llvm::SmallVector<PrimType, 8> &&ParamTypes,
+ llvm::DenseMap<unsigned, ParamDescriptor> &&Params)
+ : P(P), Loc(F->getBeginLoc()), F(F), ArgSize(ArgSize),
+ ParamTypes(std::move(ParamTypes)), Params(std::move(Params)) {}
+
+CodePtr Function::getCodeBegin() const { return Code.data(); }
+
+CodePtr Function::getCodeEnd() const { return Code.data() + Code.size(); }
+
+Function::ParamDescriptor Function::getParamDescriptor(unsigned Offset) const {
+ auto It = Params.find(Offset);
+ assert(It != Params.end() && "Invalid parameter offset");
+ return It->second;
+}
+
+SourceInfo Function::getSource(CodePtr PC) const {
+ unsigned Offset = PC - getCodeBegin();
+ using Elem = std::pair<unsigned, SourceInfo>;
+ auto It = std::lower_bound(SrcMap.begin(), SrcMap.end(), Elem{Offset, {}},
+ [](Elem A, Elem B) { return A.first < B.first; });
+ if (It == SrcMap.end() || It->first != Offset)
+ llvm::report_fatal_error("missing source location");
+ return It->second;
+}
+
+bool Function::isVirtual() const {
+ if (auto *M = dyn_cast<CXXMethodDecl>(F))
+ return M->isVirtual();
+ return false;
+}
diff --git a/lib/AST/Interp/Function.h b/lib/AST/Interp/Function.h
new file mode 100644
index 000000000000..28531f04b6e9
--- /dev/null
+++ b/lib/AST/Interp/Function.h
@@ -0,0 +1,163 @@
+//===--- Function.h - Bytecode function for the VM --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the Function class which holds all bytecode function-specific data.
+//
+// The scope class which describes local variables is also defined here.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_FUNCTION_H
+#define LLVM_CLANG_AST_INTERP_FUNCTION_H
+
+#include "Pointer.h"
+#include "Source.h"
+#include "clang/AST/Decl.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace interp {
+class Program;
+class ByteCodeEmitter;
+enum PrimType : uint32_t;
+
+/// Describes a scope block.
+///
+/// The block gathers all the descriptors of the locals defined in this block.
+class Scope {
+public:
+ /// Information about a local's storage.
+ struct Local {
+ /// Offset of the local in frame.
+ unsigned Offset;
+ /// Descriptor of the local.
+ Descriptor *Desc;
+ };
+
+ using LocalVectorTy = llvm::SmallVector<Local, 8>;
+
+ Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {}
+
+ llvm::iterator_range<LocalVectorTy::iterator> locals() {
+ return llvm::make_range(Descriptors.begin(), Descriptors.end());
+ }
+
+private:
+ /// Object descriptors in this block.
+ LocalVectorTy Descriptors;
+};
+
+/// Bytecode function.
+///
+/// Contains links to the bytecode of the function, as well as metadata
+/// describing all arguments and stack-local variables.
+class Function {
+public:
+ using ParamDescriptor = std::pair<PrimType, Descriptor *>;
+
+ /// Returns the size of the function's local stack.
+ unsigned getFrameSize() const { return FrameSize; }
+ /// Returns the size of the argument stackx
+ unsigned getArgSize() const { return ArgSize; }
+
+ /// Returns a pointer to the start of the code.
+ CodePtr getCodeBegin() const;
+ /// Returns a pointer to the end of the code.
+ CodePtr getCodeEnd() const;
+
+ /// Returns the original FunctionDecl.
+ const FunctionDecl *getDecl() const { return F; }
+
+ /// Returns the lcoation.
+ SourceLocation getLoc() const { return Loc; }
+
+ /// Returns a parameter descriptor.
+ ParamDescriptor getParamDescriptor(unsigned Offset) const;
+
+ /// Checks if the first argument is a RVO pointer.
+ bool hasRVO() const { return ParamTypes.size() != Params.size(); }
+
+ /// Range over the scope blocks.
+ llvm::iterator_range<llvm::SmallVector<Scope, 2>::iterator> scopes() {
+ return llvm::make_range(Scopes.begin(), Scopes.end());
+ }
+
+ /// Range over argument types.
+ using arg_reverse_iterator = SmallVectorImpl<PrimType>::reverse_iterator;
+ llvm::iterator_range<arg_reverse_iterator> args_reverse() {
+ return llvm::make_range(ParamTypes.rbegin(), ParamTypes.rend());
+ }
+
+ /// Returns a specific scope.
+ Scope &getScope(unsigned Idx) { return Scopes[Idx]; }
+
+ /// Returns the source information at a given PC.
+ SourceInfo getSource(CodePtr PC) const;
+
+ /// Checks if the function is valid to call in constexpr.
+ bool isConstexpr() const { return IsValid; }
+
+ /// Checks if the function is virtual.
+ bool isVirtual() const;
+
+ /// Checks if the function is a constructor.
+ bool isConstructor() const { return isa<CXXConstructorDecl>(F); }
+
+private:
+ /// Construct a function representing an actual function.
+ Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
+ llvm::SmallVector<PrimType, 8> &&ParamTypes,
+ llvm::DenseMap<unsigned, ParamDescriptor> &&Params);
+
+ /// Sets the code of a function.
+ void setCode(unsigned NewFrameSize, std::vector<char> &&NewCode, SourceMap &&NewSrcMap,
+ llvm::SmallVector<Scope, 2> &&NewScopes) {
+ FrameSize = NewFrameSize;
+ Code = std::move(NewCode);
+ SrcMap = std::move(NewSrcMap);
+ Scopes = std::move(NewScopes);
+ IsValid = true;
+ }
+
+private:
+ friend class Program;
+ friend class ByteCodeEmitter;
+
+ /// Program reference.
+ Program &P;
+ /// Location of the executed code.
+ SourceLocation Loc;
+ /// Declaration this function was compiled from.
+ const FunctionDecl *F;
+ /// Local area size: storage + metadata.
+ unsigned FrameSize;
+ /// Size of the argument stack.
+ unsigned ArgSize;
+ /// Program code.
+ std::vector<char> Code;
+ /// Opcode-to-expression mapping.
+ SourceMap SrcMap;
+ /// List of block descriptors.
+ llvm::SmallVector<Scope, 2> Scopes;
+ /// List of argument types.
+ llvm::SmallVector<PrimType, 8> ParamTypes;
+ /// Map from byte offset to parameter descriptor.
+ llvm::DenseMap<unsigned, ParamDescriptor> Params;
+ /// Flag to indicate if the function is valid.
+ bool IsValid = false;
+
+public:
+ /// Dumps the disassembled bytecode to \c llvm::errs().
+ void dump() const;
+ void dump(llvm::raw_ostream &OS) const;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/Integral.h b/lib/AST/Interp/Integral.h
new file mode 100644
index 000000000000..7cc788070de8
--- /dev/null
+++ b/lib/AST/Interp/Integral.h
@@ -0,0 +1,269 @@
+//===--- Integral.h - Wrapper for numeric types for the VM ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the VM types and helpers operating on types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_H
+#define LLVM_CLANG_AST_INTERP_INTEGRAL_H
+
+#include "clang/AST/ComparisonCategories.h"
+#include "clang/AST/APValue.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstddef>
+#include <cstdint>
+
+namespace clang {
+namespace interp {
+
+using APInt = llvm::APInt;
+using APSInt = llvm::APSInt;
+
+/// Helper to compare two comparable types.
+template <typename T>
+ComparisonCategoryResult Compare(const T &X, const T &Y) {
+ if (X < Y)
+ return ComparisonCategoryResult::Less;
+ if (X > Y)
+ return ComparisonCategoryResult::Greater;
+ return ComparisonCategoryResult::Equal;
+}
+
+// Helper structure to select the representation.
+template <unsigned Bits, bool Signed> struct Repr;
+template <> struct Repr<8, false> { using Type = uint8_t; };
+template <> struct Repr<16, false> { using Type = uint16_t; };
+template <> struct Repr<32, false> { using Type = uint32_t; };
+template <> struct Repr<64, false> { using Type = uint64_t; };
+template <> struct Repr<8, true> { using Type = int8_t; };
+template <> struct Repr<16, true> { using Type = int16_t; };
+template <> struct Repr<32, true> { using Type = int32_t; };
+template <> struct Repr<64, true> { using Type = int64_t; };
+
+/// Wrapper around numeric types.
+///
+/// These wrappers are required to shared an interface between APSint and
+/// builtin primitive numeral types, while optimising for storage and
+/// allowing methods operating on primitive type to compile to fast code.
+template <unsigned Bits, bool Signed> class Integral {
+private:
+ template <unsigned OtherBits, bool OtherSigned> friend class Integral;
+
+ // The primitive representing the integral.
+ using T = typename Repr<Bits, Signed>::Type;
+ T V;
+
+ /// Primitive representing limits.
+ static const auto Min = std::numeric_limits<T>::min();
+ static const auto Max = std::numeric_limits<T>::max();
+
+ /// Construct an integral from anything that is convertible to storage.
+ template <typename T> explicit Integral(T V) : V(V) {}
+
+public:
+ /// Zero-initializes an integral.
+ Integral() : V(0) {}
+
+ /// Constructs an integral from another integral.
+ template <unsigned SrcBits, bool SrcSign>
+ explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {}
+
+ /// Construct an integral from a value based on signedness.
+ explicit Integral(const APSInt &V)
+ : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {}
+
+ bool operator<(Integral RHS) const { return V < RHS.V; }
+ bool operator>(Integral RHS) const { return V > RHS.V; }
+ bool operator<=(Integral RHS) const { return V <= RHS.V; }
+ bool operator>=(Integral RHS) const { return V >= RHS.V; }
+ bool operator==(Integral RHS) const { return V == RHS.V; }
+ bool operator!=(Integral RHS) const { return V != RHS.V; }
+
+ bool operator>(unsigned RHS) const {
+ return V >= 0 && static_cast<unsigned>(V) > RHS;
+ }
+
+ Integral operator-() const { return Integral(-V); }
+ Integral operator~() const { return Integral(~V); }
+
+ template <unsigned DstBits, bool DstSign>
+ explicit operator Integral<DstBits, DstSign>() const {
+ return Integral<DstBits, DstSign>(V);
+ }
+
+ explicit operator unsigned() const { return V; }
+ explicit operator int64_t() const { return V; }
+ explicit operator uint64_t() const { return V; }
+
+ APSInt toAPSInt() const {
+ return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
+ }
+ APSInt toAPSInt(unsigned NumBits) const {
+ if (Signed)
+ return APSInt(toAPSInt().sextOrTrunc(NumBits), !Signed);
+ else
+ return APSInt(toAPSInt().zextOrTrunc(NumBits), !Signed);
+ }
+ APValue toAPValue() const { return APValue(toAPSInt()); }
+
+ Integral<Bits, false> toUnsigned() const {
+ return Integral<Bits, false>(*this);
+ }
+
+ constexpr static unsigned bitWidth() { return Bits; }
+
+ bool isZero() const { return !V; }
+
+ bool isMin() const { return *this == min(bitWidth()); }
+
+ bool isMinusOne() const { return Signed && V == T(-1); }
+
+ constexpr static bool isSigned() { return Signed; }
+
+ bool isNegative() const { return V < T(0); }
+ bool isPositive() const { return !isNegative(); }
+
+ ComparisonCategoryResult compare(const Integral &RHS) const {
+ return Compare(V, RHS.V);
+ }
+
+ unsigned countLeadingZeros() const { return llvm::countLeadingZeros<T>(V); }
+
+ Integral truncate(unsigned TruncBits) const {
+ if (TruncBits >= Bits)
+ return *this;
+ const T BitMask = (T(1) << T(TruncBits)) - 1;
+ const T SignBit = T(1) << (TruncBits - 1);
+ const T ExtMask = ~BitMask;
+ return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));
+ }
+
+ void print(llvm::raw_ostream &OS) const { OS << V; }
+
+ static Integral min(unsigned NumBits) {
+ return Integral(Min);
+ }
+ static Integral max(unsigned NumBits) {
+ return Integral(Max);
+ }
+
+ template <typename T>
+ static typename std::enable_if<std::is_integral<T>::value, Integral>::type
+ from(T Value) {
+ return Integral(Value);
+ }
+
+ template <unsigned SrcBits, bool SrcSign>
+ static typename std::enable_if<SrcBits != 0, Integral>::type
+ from(Integral<SrcBits, SrcSign> Value) {
+ return Integral(Value.V);
+ }
+
+ template <bool SrcSign> static Integral from(Integral<0, SrcSign> Value) {
+ if (SrcSign)
+ return Integral(Value.V.getSExtValue());
+ else
+ return Integral(Value.V.getZExtValue());
+ }
+
+ static Integral zero() { return from(0); }
+
+ template <typename T> static Integral from(T Value, unsigned NumBits) {
+ return Integral(Value);
+ }
+
+ static bool inRange(int64_t Value, unsigned NumBits) {
+ return CheckRange<T, Min, Max>(Value);
+ }
+
+ static bool increment(Integral A, Integral *R) {
+ return add(A, Integral(T(1)), A.bitWidth(), R);
+ }
+
+ static bool decrement(Integral A, Integral *R) {
+ return sub(A, Integral(T(1)), A.bitWidth(), R);
+ }
+
+ static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ return CheckAddUB(A.V, B.V, R->V);
+ }
+
+ static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ return CheckSubUB(A.V, B.V, R->V);
+ }
+
+ static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ return CheckMulUB(A.V, B.V, R->V);
+ }
+
+private:
+ template <typename T>
+ static typename std::enable_if<std::is_signed<T>::value, bool>::type
+ CheckAddUB(T A, T B, T &R) {
+ return llvm::AddOverflow<T>(A, B, R);
+ }
+
+ template <typename T>
+ static typename std::enable_if<std::is_unsigned<T>::value, bool>::type
+ CheckAddUB(T A, T B, T &R) {
+ R = A + B;
+ return false;
+ }
+
+ template <typename T>
+ static typename std::enable_if<std::is_signed<T>::value, bool>::type
+ CheckSubUB(T A, T B, T &R) {
+ return llvm::SubOverflow<T>(A, B, R);
+ }
+
+ template <typename T>
+ static typename std::enable_if<std::is_unsigned<T>::value, bool>::type
+ CheckSubUB(T A, T B, T &R) {
+ R = A - B;
+ return false;
+ }
+
+ template <typename T>
+ static typename std::enable_if<std::is_signed<T>::value, bool>::type
+ CheckMulUB(T A, T B, T &R) {
+ return llvm::MulOverflow<T>(A, B, R);
+ }
+
+ template <typename T>
+ static typename std::enable_if<std::is_unsigned<T>::value, bool>::type
+ CheckMulUB(T A, T B, T &R) {
+ R = A * B;
+ return false;
+ }
+
+ template <typename T, T Min, T Max>
+ static typename std::enable_if<std::is_signed<T>::value, bool>::type
+ CheckRange(int64_t V) {
+ return Min <= V && V <= Max;
+ }
+
+ template <typename T, T Min, T Max>
+ static typename std::enable_if<std::is_unsigned<T>::value, bool>::type
+ CheckRange(int64_t V) {
+ return V >= 0 && static_cast<uint64_t>(V) <= Max;
+ }
+};
+
+template <unsigned Bits, bool Signed>
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) {
+ I.print(OS);
+ return OS;
+}
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/Interp.cpp b/lib/AST/Interp/Interp.cpp
new file mode 100644
index 000000000000..1a8109cedf76
--- /dev/null
+++ b/lib/AST/Interp/Interp.cpp
@@ -0,0 +1,417 @@
+//===--- InterpState.cpp - Interpreter for the constexpr VM -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Interp.h"
+#include <limits>
+#include <vector>
+#include "Function.h"
+#include "InterpFrame.h"
+#include "InterpStack.h"
+#include "Opcode.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "State.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "llvm/ADT/APSInt.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+//===----------------------------------------------------------------------===//
+// Ret
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+static bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
+ S.CallStackDepth--;
+ const T &Ret = S.Stk.pop<T>();
+
+ assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
+ if (!S.checkingPotentialConstantExpression())
+ S.Current->popArgs();
+
+ if (InterpFrame *Caller = S.Current->Caller) {
+ PC = S.Current->getRetPC();
+ delete S.Current;
+ S.Current = Caller;
+ S.Stk.push<T>(Ret);
+ } else {
+ delete S.Current;
+ S.Current = nullptr;
+ if (!ReturnValue<T>(Ret, Result))
+ return false;
+ }
+ return true;
+}
+
+static bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
+ S.CallStackDepth--;
+
+ assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");
+ if (!S.checkingPotentialConstantExpression())
+ S.Current->popArgs();
+
+ if (InterpFrame *Caller = S.Current->Caller) {
+ PC = S.Current->getRetPC();
+ delete S.Current;
+ S.Current = Caller;
+ } else {
+ delete S.Current;
+ S.Current = nullptr;
+ }
+ return true;
+}
+
+static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) {
+ llvm::report_fatal_error("Interpreter cannot return values");
+}
+
+//===----------------------------------------------------------------------===//
+// Jmp, Jt, Jf
+//===----------------------------------------------------------------------===//
+
+static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
+ PC += Offset;
+ return true;
+}
+
+static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {
+ if (S.Stk.pop<bool>()) {
+ PC += Offset;
+ }
+ return true;
+}
+
+static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
+ if (!S.Stk.pop<bool>()) {
+ PC += Offset;
+ }
+ return true;
+}
+
+static bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
+ if (Ptr.isInitialized())
+ return true;
+ if (!S.checkingPotentialConstantExpression()) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_access_uninit) << AK << false;
+ }
+ return false;
+}
+
+static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
+ if (Ptr.isActive())
+ return true;
+
+ // Get the inactive field descriptor.
+ const FieldDecl *InactiveField = Ptr.getField();
+
+ // Walk up the pointer chain to find the union which is not active.
+ Pointer U = Ptr.getBase();
+ while (!U.isActive()) {
+ U = U.getBase();
+ }
+
+ // Find the active field of the union.
+ Record *R = U.getRecord();
+ assert(R && R->isUnion() && "Not a union");
+ const FieldDecl *ActiveField = nullptr;
+ for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) {
+ const Pointer &Field = U.atField(R->getField(I)->Offset);
+ if (Field.isActive()) {
+ ActiveField = Field.getField();
+ break;
+ }
+ }
+
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)
+ << AK << InactiveField << !ActiveField << ActiveField;
+ return false;
+}
+
+static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
+ if (auto ID = Ptr.getDeclID()) {
+ if (!Ptr.isStaticTemporary())
+ return true;
+
+ if (Ptr.getDeclDesc()->getType().isConstQualified())
+ return true;
+
+ if (S.P.getCurrentDecl() == ID)
+ return true;
+
+ const SourceInfo &E = S.Current->getSource(OpPC);
+ S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
+ S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
+ return false;
+ }
+ return true;
+}
+
+static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ if (auto ID = Ptr.getDeclID()) {
+ if (!Ptr.isStatic())
+ return true;
+
+ if (S.P.getCurrentDecl() == ID)
+ return true;
+
+ S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
+ return false;
+ }
+ return true;
+}
+
+namespace clang {
+namespace interp {
+
+bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ if (!Ptr.isExtern())
+ return true;
+
+ if (!S.checkingPotentialConstantExpression()) {
+ auto *VD = Ptr.getDeclDesc()->asValueDecl();
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
+ S.Note(VD->getLocation(), diag::note_declared_at);
+ }
+ return false;
+}
+
+bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ if (!Ptr.isUnknownSizeArray())
+ return true;
+ const SourceInfo &E = S.Current->getSource(OpPC);
+ S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);
+ return false;
+}
+
+bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
+ const auto &Src = S.Current->getSource(OpPC);
+ if (Ptr.isZero()) {
+
+ if (Ptr.isField())
+ S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
+ else
+ S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
+
+ return false;
+ }
+
+ if (!Ptr.isLive()) {
+ bool IsTemp = Ptr.isTemporary();
+
+ S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
+
+ if (IsTemp)
+ S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
+ else
+ S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
+
+ return false;
+ }
+
+ return true;
+}
+
+bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ CheckSubobjectKind CSK) {
+ if (!Ptr.isZero())
+ return true;
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK;
+ return false;
+}
+
+bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
+ if (!Ptr.isOnePastEnd())
+ return true;
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_access_past_end) << AK;
+ return false;
+}
+
+bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ CheckSubobjectKind CSK) {
+ if (!Ptr.isElementPastEnd())
+ return true;
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK;
+ return false;
+}
+
+bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ assert(Ptr.isLive() && "Pointer is not live");
+ if (!Ptr.isConst()) {
+ return true;
+ }
+
+ const QualType Ty = Ptr.getType();
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
+ return false;
+}
+
+bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ assert(Ptr.isLive() && "Pointer is not live");
+ if (!Ptr.isMutable()) {
+ return true;
+ }
+
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ const FieldDecl *Field = Ptr.getField();
+ S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;
+ S.Note(Field->getLocation(), diag::note_declared_at);
+ return false;
+}
+
+bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ if (!CheckLive(S, OpPC, Ptr, AK_Read))
+ return false;
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, AK_Read))
+ return false;
+ if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
+ return false;
+ if (!CheckActive(S, OpPC, Ptr, AK_Read))
+ return false;
+ if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
+ return false;
+ if (!CheckMutable(S, OpPC, Ptr))
+ return false;
+ return true;
+}
+
+bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ if (!CheckLive(S, OpPC, Ptr, AK_Assign))
+ return false;
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, AK_Assign))
+ return false;
+ if (!CheckGlobal(S, OpPC, Ptr))
+ return false;
+ if (!CheckConst(S, OpPC, Ptr))
+ return false;
+ return true;
+}
+
+bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
+ return false;
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
+ return false;
+ return true;
+}
+
+bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ if (!CheckLive(S, OpPC, Ptr, AK_Assign))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, AK_Assign))
+ return false;
+ return true;
+}
+
+bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F) {
+ const SourceLocation &Loc = S.Current->getLocation(OpPC);
+
+ if (F->isVirtual()) {
+ if (!S.getLangOpts().CPlusPlus2a) {
+ S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
+ return false;
+ }
+ }
+
+ if (!F->isConstexpr()) {
+ if (S.getLangOpts().CPlusPlus11) {
+ const FunctionDecl *DiagDecl = F->getDecl();
+
+ // If this function is not constexpr because it is an inherited
+ // non-constexpr constructor, diagnose that directly.
+ auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
+ if (CD && CD->isInheritingConstructor()) {
+ auto *Inherited = CD->getInheritedConstructor().getConstructor();
+ if (!Inherited->isConstexpr())
+ DiagDecl = CD = Inherited;
+ }
+
+ // FIXME: If DiagDecl is an implicitly-declared special member function
+ // or an inheriting constructor, we should be much more explicit about why
+ // it's not constexpr.
+ if (CD && CD->isInheritingConstructor())
+ S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
+ << CD->getInheritedConstructor().getConstructor()->getParent();
+ else
+ S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
+ << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
+ S.Note(DiagDecl->getLocation(), diag::note_declared_at);
+ } else {
+ S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {
+ if (!This.isZero())
+ return true;
+
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+
+ bool IsImplicit = false;
+ if (auto *E = dyn_cast_or_null<CXXThisExpr>(Loc.asExpr()))
+ IsImplicit = E->isImplicit();
+
+ if (S.getLangOpts().CPlusPlus11)
+ S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;
+ else
+ S.FFDiag(Loc);
+
+ return false;
+}
+
+bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
+ if (!MD->isPure())
+ return true;
+ const SourceInfo &E = S.Current->getSource(OpPC);
+ S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;
+ S.Note(MD->getLocation(), diag::note_declared_at);
+ return false;
+}
+bool Interpret(InterpState &S, APValue &Result) {
+ CodePtr PC = S.Current->getPC();
+
+ for (;;) {
+ auto Op = PC.read<Opcode>();
+ CodePtr OpPC = PC;
+
+ switch (Op) {
+#define GET_INTERP
+#include "Opcodes.inc"
+#undef GET_INTERP
+ }
+ }
+}
+
+} // namespace interp
+} // namespace clang
diff --git a/lib/AST/Interp/Interp.h b/lib/AST/Interp/Interp.h
new file mode 100644
index 000000000000..8934efa13b9c
--- /dev/null
+++ b/lib/AST/Interp/Interp.h
@@ -0,0 +1,960 @@
+//===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Definition of the interpreter state and entry point.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_INTERP_H
+#define LLVM_CLANG_AST_INTERP_INTERP_H
+
+#include <limits>
+#include <vector>
+#include "Function.h"
+#include "InterpFrame.h"
+#include "InterpStack.h"
+#include "InterpState.h"
+#include "Opcode.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "State.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/Expr.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/Support/Endian.h"
+
+namespace clang {
+namespace interp {
+
+using APInt = llvm::APInt;
+using APSInt = llvm::APSInt;
+
+/// Convers a value to an APValue.
+template <typename T> bool ReturnValue(const T &V, APValue &R) {
+ R = V.toAPValue();
+ return true;
+}
+
+/// Checks if the variable has externally defined storage.
+bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if the array is offsetable.
+bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a pointer is live and accesible.
+bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK);
+/// Checks if a pointer is null.
+bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ CheckSubobjectKind CSK);
+
+/// Checks if a pointer is in range.
+bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK);
+
+/// Checks if a field from which a pointer is going to be derived is valid.
+bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ CheckSubobjectKind CSK);
+
+/// Checks if a pointer points to const storage.
+bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a pointer points to a mutable field.
+bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a value can be loaded from a block.
+bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a value can be stored in a block.
+bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a method can be invoked on an object.
+bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a value can be initialized.
+bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+
+/// Checks if a method can be called.
+bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F);
+
+/// Checks the 'this' pointer.
+bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
+
+/// Checks if a method is pure virtual.
+bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
+
+template <typename T> inline bool IsTrue(const T &V) { return !V.isZero(); }
+
+//===----------------------------------------------------------------------===//
+// Add, Sub, Mul
+//===----------------------------------------------------------------------===//
+
+template <typename T, bool (*OpFW)(T, T, unsigned, T *),
+ template <typename U> class OpAP>
+bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
+ const T &RHS) {
+ // Fast path - add the numbers with fixed width.
+ T Result;
+ if (!OpFW(LHS, RHS, Bits, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+
+ // If for some reason evaluation continues, use the truncated results.
+ S.Stk.push<T>(Result);
+
+ // Slow path - compute the result using another bit of precision.
+ APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
+
+ // Report undefined behaviour, stopping if required.
+ const Expr *E = S.Current->getExpr(OpPC);
+ QualType Type = E->getType();
+ if (S.checkingForUndefinedBehavior()) {
+ auto Trunc = Value.trunc(Result.bitWidth()).toString(10);
+ auto Loc = E->getExprLoc();
+ S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
+ return true;
+ } else {
+ S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
+ return S.noteUndefinedBehavior();
+ }
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Add(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+ const unsigned Bits = RHS.bitWidth() + 1;
+ return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Sub(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+ const unsigned Bits = RHS.bitWidth() + 1;
+ return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Mul(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+ const unsigned Bits = RHS.bitWidth() * 2;
+ return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
+}
+
+//===----------------------------------------------------------------------===//
+// EQ, NE, GT, GE, LT, LE
+//===----------------------------------------------------------------------===//
+
+using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
+
+template <typename T>
+bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
+ using BoolT = PrimConv<PT_Bool>::T;
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+ S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
+ return true;
+}
+
+template <typename T>
+bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
+ return CmpHelper<T>(S, OpPC, Fn);
+}
+
+template <>
+inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
+ using BoolT = PrimConv<PT_Bool>::T;
+ const Pointer &RHS = S.Stk.pop<Pointer>();
+ const Pointer &LHS = S.Stk.pop<Pointer>();
+
+ if (!Pointer::hasSameBase(LHS, RHS)) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
+ return false;
+ } else {
+ unsigned VL = LHS.getByteOffset();
+ unsigned VR = RHS.getByteOffset();
+ S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
+ return true;
+ }
+}
+
+template <>
+inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
+ using BoolT = PrimConv<PT_Bool>::T;
+ const Pointer &RHS = S.Stk.pop<Pointer>();
+ const Pointer &LHS = S.Stk.pop<Pointer>();
+
+ if (LHS.isZero() || RHS.isZero()) {
+ if (LHS.isZero() && RHS.isZero())
+ S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
+ else
+ S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Nonequal)));
+ return true;
+ }
+
+ if (!Pointer::hasSameBase(LHS, RHS)) {
+ S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
+ return true;
+ } else {
+ unsigned VL = LHS.getByteOffset();
+ unsigned VR = RHS.getByteOffset();
+ S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
+ return true;
+ }
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool EQ(InterpState &S, CodePtr OpPC) {
+ return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
+ return R == ComparisonCategoryResult::Equal;
+ });
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool NE(InterpState &S, CodePtr OpPC) {
+ return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
+ return R != ComparisonCategoryResult::Equal;
+ });
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool LT(InterpState &S, CodePtr OpPC) {
+ return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
+ return R == ComparisonCategoryResult::Less;
+ });
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool LE(InterpState &S, CodePtr OpPC) {
+ return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
+ return R == ComparisonCategoryResult::Less ||
+ R == ComparisonCategoryResult::Equal;
+ });
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GT(InterpState &S, CodePtr OpPC) {
+ return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
+ return R == ComparisonCategoryResult::Greater;
+ });
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GE(InterpState &S, CodePtr OpPC) {
+ return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
+ return R == ComparisonCategoryResult::Greater ||
+ R == ComparisonCategoryResult::Equal;
+ });
+}
+
+//===----------------------------------------------------------------------===//
+// InRange
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InRange(InterpState &S, CodePtr OpPC) {
+ const T RHS = S.Stk.pop<T>();
+ const T LHS = S.Stk.pop<T>();
+ const T Value = S.Stk.pop<T>();
+
+ S.Stk.push<bool>(LHS <= Value && Value <= RHS);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Dup, Pop, Test
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Dup(InterpState &S, CodePtr OpPC) {
+ S.Stk.push<T>(S.Stk.peek<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Pop(InterpState &S, CodePtr OpPC) {
+ S.Stk.pop<T>();
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Const
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
+ S.Stk.push<T>(Arg);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Get/Set Local/Param/Global/This
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
+ S.Stk.push<T>(S.Current->getLocal<T>(I));
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
+ S.Current->setLocal<T>(I, S.Stk.pop<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
+ if (S.checkingPotentialConstantExpression()) {
+ return false;
+ }
+ S.Stk.push<T>(S.Current->getParam<T>(I));
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
+ S.Current->setParam<T>(I, S.Stk.pop<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
+ const Pointer &Obj = S.Stk.peek<Pointer>();
+ if (!CheckNull(S, OpPC, Obj, CSK_Field))
+ return false;
+ if (!CheckRange(S, OpPC, Obj, CSK_Field))
+ return false;
+ const Pointer &Field = Obj.atField(I);
+ if (!CheckLoad(S, OpPC, Field))
+ return false;
+ S.Stk.push<T>(Field.deref<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Obj = S.Stk.peek<Pointer>();
+ if (!CheckNull(S, OpPC, Obj, CSK_Field))
+ return false;
+ if (!CheckRange(S, OpPC, Obj, CSK_Field))
+ return false;
+ const Pointer &Field = Obj.atField(I);
+ if (!CheckStore(S, OpPC, Field))
+ return false;
+ Field.deref<T>() = Value;
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
+ const Pointer &Obj = S.Stk.pop<Pointer>();
+ if (!CheckNull(S, OpPC, Obj, CSK_Field))
+ return false;
+ if (!CheckRange(S, OpPC, Obj, CSK_Field))
+ return false;
+ const Pointer &Field = Obj.atField(I);
+ if (!CheckLoad(S, OpPC, Field))
+ return false;
+ S.Stk.push<T>(Field.deref<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ const Pointer &Field = This.atField(I);
+ if (!CheckLoad(S, OpPC, Field))
+ return false;
+ S.Stk.push<T>(Field.deref<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ const Pointer &Field = This.atField(I);
+ if (!CheckStore(S, OpPC, Field))
+ return false;
+ Field.deref<T>() = Value;
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
+ auto *B = S.P.getGlobal(I);
+ if (B->isExtern())
+ return false;
+ S.Stk.push<T>(B->deref<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
+ // TODO: emit warning.
+ return false;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
+ S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ const Pointer &Field = This.atField(I);
+ Field.deref<T>() = S.Stk.pop<T>();
+ Field.initialize();
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ const Pointer &Field = This.atField(F->Offset);
+ const auto &Value = S.Stk.pop<T>();
+ Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
+ Field.initialize();
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ const Pointer &Field = This.atField(I);
+ Field.deref<T>() = S.Stk.pop<T>();
+ Field.activate();
+ Field.initialize();
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Field = S.Stk.pop<Pointer>().atField(I);
+ Field.deref<T>() = Value;
+ Field.activate();
+ Field.initialize();
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
+ Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
+ Field.activate();
+ Field.initialize();
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ const Pointer &Field = Ptr.atField(I);
+ Field.deref<T>() = Value;
+ Field.activate();
+ Field.initialize();
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// GetPtr Local/Param/Global/Field/This
+//===----------------------------------------------------------------------===//
+
+inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
+ S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
+ return true;
+}
+
+inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
+ if (S.checkingPotentialConstantExpression()) {
+ return false;
+ }
+ S.Stk.push<Pointer>(S.Current->getParamPointer(I));
+ return true;
+}
+
+inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
+ S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
+ return true;
+}
+
+inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckNull(S, OpPC, Ptr, CSK_Field))
+ return false;
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, CSK_Field))
+ return false;
+ S.Stk.push<Pointer>(Ptr.atField(Off));
+ return true;
+}
+
+inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ S.Stk.push<Pointer>(This.atField(Off));
+ return true;
+}
+
+inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckNull(S, OpPC, Ptr, CSK_Field))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, CSK_Field))
+ return false;
+ Pointer Field = Ptr.atField(Off);
+ Ptr.deactivate();
+ Field.activate();
+ S.Stk.push<Pointer>(std::move(Field));
+ return true;
+}
+
+inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ Pointer Field = This.atField(Off);
+ This.deactivate();
+ Field.activate();
+ S.Stk.push<Pointer>(std::move(Field));
+ return true;
+}
+
+inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckNull(S, OpPC, Ptr, CSK_Base))
+ return false;
+ S.Stk.push<Pointer>(Ptr.atField(Off));
+ return true;
+}
+
+inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ S.Stk.push<Pointer>(This.atField(Off));
+ return true;
+}
+
+inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
+ const Pointer &Ptr) {
+ Pointer Base = Ptr;
+ while (Base.isBaseClass())
+ Base = Base.getBase();
+
+ auto *Field = Base.getRecord()->getVirtualBase(Decl);
+ S.Stk.push<Pointer>(Base.atField(Field->Offset));
+ return true;
+}
+
+inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckNull(S, OpPC, Ptr, CSK_Base))
+ return false;
+ return VirtBaseHelper(S, OpPC, D, Ptr);
+}
+
+inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
+ const RecordDecl *D) {
+ if (S.checkingPotentialConstantExpression())
+ return false;
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+ return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
+}
+
+//===----------------------------------------------------------------------===//
+// Load, Store, Init
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Load(InterpState &S, CodePtr OpPC) {
+ const Pointer &Ptr = S.Stk.peek<Pointer>();
+ if (!CheckLoad(S, OpPC, Ptr))
+ return false;
+ S.Stk.push<T>(Ptr.deref<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool LoadPop(InterpState &S, CodePtr OpPC) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckLoad(S, OpPC, Ptr))
+ return false;
+ S.Stk.push<T>(Ptr.deref<T>());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Store(InterpState &S, CodePtr OpPC) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.peek<Pointer>();
+ if (!CheckStore(S, OpPC, Ptr))
+ return false;
+ Ptr.deref<T>() = Value;
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool StorePop(InterpState &S, CodePtr OpPC) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckStore(S, OpPC, Ptr))
+ return false;
+ Ptr.deref<T>() = Value;
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool StoreBitField(InterpState &S, CodePtr OpPC) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.peek<Pointer>();
+ if (!CheckStore(S, OpPC, Ptr))
+ return false;
+ if (auto *FD = Ptr.getField()) {
+ Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
+ } else {
+ Ptr.deref<T>() = Value;
+ }
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckStore(S, OpPC, Ptr))
+ return false;
+ if (auto *FD = Ptr.getField()) {
+ Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
+ } else {
+ Ptr.deref<T>() = Value;
+ }
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitPop(InterpState &S, CodePtr OpPC) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckInit(S, OpPC, Ptr))
+ return false;
+ Ptr.initialize();
+ new (&Ptr.deref<T>()) T(Value);
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
+ if (!CheckInit(S, OpPC, Ptr))
+ return false;
+ Ptr.initialize();
+ new (&Ptr.deref<T>()) T(Value);
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
+ const T &Value = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
+ if (!CheckInit(S, OpPC, Ptr))
+ return false;
+ Ptr.initialize();
+ new (&Ptr.deref<T>()) T(Value);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// AddOffset, SubOffset
+//===----------------------------------------------------------------------===//
+
+template <class T, bool Add> bool OffsetHelper(InterpState &S, CodePtr OpPC) {
+ // Fetch the pointer and the offset.
+ const T &Offset = S.Stk.pop<T>();
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
+ return false;
+ if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
+ return false;
+
+ // Get a version of the index comparable to the type.
+ T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
+ // A zero offset does not change the pointer, but in the case of an array
+ // it has to be adjusted to point to the first element instead of the array.
+ if (Offset.isZero()) {
+ S.Stk.push<Pointer>(Index.isZero() ? Ptr.atIndex(0) : Ptr);
+ return true;
+ }
+ // Arrays of unknown bounds cannot have pointers into them.
+ if (!CheckArray(S, OpPC, Ptr))
+ return false;
+
+ // Compute the largest index into the array.
+ unsigned MaxIndex = Ptr.getNumElems();
+
+ // Helper to report an invalid offset, computed as APSInt.
+ auto InvalidOffset = [&]() {
+ const unsigned Bits = Offset.bitWidth();
+ APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
+ APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
+ APSInt NewIndex = Add ? (APIndex + APOffset) : (APIndex - APOffset);
+ S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
+ << NewIndex
+ << /*array*/ static_cast<int>(!Ptr.inArray())
+ << static_cast<unsigned>(MaxIndex);
+ return false;
+ };
+
+ // If the new offset would be negative, bail out.
+ if (Add && Offset.isNegative() && (Offset.isMin() || -Offset > Index))
+ return InvalidOffset();
+ if (!Add && Offset.isPositive() && Index < Offset)
+ return InvalidOffset();
+
+ // If the new offset would be out of bounds, bail out.
+ unsigned MaxOffset = MaxIndex - Ptr.getIndex();
+ if (Add && Offset.isPositive() && Offset > MaxOffset)
+ return InvalidOffset();
+ if (!Add && Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
+ return InvalidOffset();
+
+ // Offset is valid - compute it on unsigned.
+ int64_t WideIndex = static_cast<int64_t>(Index);
+ int64_t WideOffset = static_cast<int64_t>(Offset);
+ int64_t Result = Add ? (WideIndex + WideOffset) : (WideIndex - WideOffset);
+ S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool AddOffset(InterpState &S, CodePtr OpPC) {
+ return OffsetHelper<T, true>(S, OpPC);
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool SubOffset(InterpState &S, CodePtr OpPC) {
+ return OffsetHelper<T, false>(S, OpPC);
+}
+
+
+//===----------------------------------------------------------------------===//
+// Destroy
+//===----------------------------------------------------------------------===//
+
+inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
+ S.Current->destroy(I);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Cast, CastFP
+//===----------------------------------------------------------------------===//
+
+template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
+ using T = typename PrimConv<TIn>::T;
+ using U = typename PrimConv<TOut>::T;
+ S.Stk.push<U>(U::from(S.Stk.pop<T>()));
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Zero, Nullptr
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Zero(InterpState &S, CodePtr OpPC) {
+ S.Stk.push<T>(T::zero());
+ return true;
+}
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+inline bool Null(InterpState &S, CodePtr OpPC) {
+ S.Stk.push<T>();
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// This, ImplicitThis
+//===----------------------------------------------------------------------===//
+
+inline bool This(InterpState &S, CodePtr OpPC) {
+ // Cannot read 'this' in this mode.
+ if (S.checkingPotentialConstantExpression()) {
+ return false;
+ }
+
+ const Pointer &This = S.Current->getThis();
+ if (!CheckThis(S, OpPC, This))
+ return false;
+
+ S.Stk.push<Pointer>(This);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Shr, Shl
+//===----------------------------------------------------------------------===//
+
+template <PrimType TR, PrimType TL, class T = typename PrimConv<TR>::T>
+unsigned Trunc(InterpState &S, CodePtr OpPC, unsigned Bits, const T &V) {
+ // C++11 [expr.shift]p1: Shift width must be less than the bit width of
+ // the shifted type.
+ if (Bits > 1 && V >= T::from(Bits, V.bitWidth())) {
+ const Expr *E = S.Current->getExpr(OpPC);
+ const APSInt Val = V.toAPSInt();
+ QualType Ty = E->getType();
+ S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
+ return Bits;
+ } else {
+ return static_cast<unsigned>(V);
+ }
+}
+
+template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
+inline bool ShiftRight(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) {
+ if (RHS >= V.bitWidth()) {
+ S.Stk.push<T>(T::from(0, V.bitWidth()));
+ } else {
+ S.Stk.push<T>(T::from(V >> RHS, V.bitWidth()));
+ }
+ return true;
+}
+
+template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
+inline bool ShiftLeft(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) {
+ if (V.isSigned() && !S.getLangOpts().CPlusPlus2a) {
+ // C++11 [expr.shift]p2: A signed left shift must have a non-negative
+ // operand, and must not overflow the corresponding unsigned type.
+ // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
+ // E1 x 2^E2 module 2^N.
+ if (V.isNegative()) {
+ const Expr *E = S.Current->getExpr(OpPC);
+ S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << V.toAPSInt();
+ } else if (V.countLeadingZeros() < RHS) {
+ S.CCEDiag(S.Current->getExpr(OpPC), diag::note_constexpr_lshift_discards);
+ }
+ }
+
+ if (V.bitWidth() == 1) {
+ S.Stk.push<T>(V);
+ } else if (RHS >= V.bitWidth()) {
+ S.Stk.push<T>(T::from(0, V.bitWidth()));
+ } else {
+ S.Stk.push<T>(T::from(V.toUnsigned() << RHS, V.bitWidth()));
+ }
+ return true;
+}
+
+template <PrimType TL, PrimType TR>
+inline bool Shr(InterpState &S, CodePtr OpPC) {
+ const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>();
+ const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>();
+ const unsigned Bits = LHS.bitWidth();
+
+ if (RHS.isSigned() && RHS.isNegative()) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
+ return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
+ } else {
+ return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
+ }
+}
+
+template <PrimType TL, PrimType TR>
+inline bool Shl(InterpState &S, CodePtr OpPC) {
+ const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>();
+ const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>();
+ const unsigned Bits = LHS.bitWidth();
+
+ if (RHS.isSigned() && RHS.isNegative()) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
+ return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
+ } else {
+ return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// NoRet
+//===----------------------------------------------------------------------===//
+
+inline bool NoRet(InterpState &S, CodePtr OpPC) {
+ SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
+ S.FFDiag(EndLoc, diag::note_constexpr_no_return);
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// NarrowPtr, ExpandPtr
+//===----------------------------------------------------------------------===//
+
+inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ S.Stk.push<Pointer>(Ptr.narrow());
+ return true;
+}
+
+inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ S.Stk.push<Pointer>(Ptr.expand());
+ return true;
+}
+
+/// Interpreter entry point.
+bool Interpret(InterpState &S, APValue &Result);
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/InterpFrame.cpp b/lib/AST/Interp/InterpFrame.cpp
new file mode 100644
index 000000000000..9d01bf0333fe
--- /dev/null
+++ b/lib/AST/Interp/InterpFrame.cpp
@@ -0,0 +1,193 @@
+//===--- InterpFrame.cpp - Call Frame implementation for the VM -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "InterpFrame.h"
+#include "Function.h"
+#include "Interp.h"
+#include "InterpStack.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+InterpFrame::InterpFrame(InterpState &S, Function *Func, InterpFrame *Caller,
+ CodePtr RetPC, Pointer &&This)
+ : Caller(Caller), S(S), Func(Func), This(std::move(This)), RetPC(RetPC),
+ ArgSize(Func ? Func->getArgSize() : 0),
+ Args(static_cast<char *>(S.Stk.top())), FrameOffset(S.Stk.size()) {
+ if (Func) {
+ if (unsigned FrameSize = Func->getFrameSize()) {
+ Locals = std::make_unique<char[]>(FrameSize);
+ for (auto &Scope : Func->scopes()) {
+ for (auto &Local : Scope.locals()) {
+ Block *B = new (localBlock(Local.Offset)) Block(Local.Desc);
+ B->invokeCtor();
+ }
+ }
+ }
+ }
+}
+
+InterpFrame::~InterpFrame() {
+ if (Func && Func->isConstructor() && This.isBaseClass())
+ This.initialize();
+ for (auto &Param : Params)
+ S.deallocate(reinterpret_cast<Block *>(Param.second.get()));
+}
+
+void InterpFrame::destroy(unsigned Idx) {
+ for (auto &Local : Func->getScope(Idx).locals()) {
+ S.deallocate(reinterpret_cast<Block *>(localBlock(Local.Offset)));
+ }
+}
+
+void InterpFrame::popArgs() {
+ for (PrimType Ty : Func->args_reverse())
+ TYPE_SWITCH(Ty, S.Stk.discard<T>());
+}
+
+template <typename T>
+static void print(llvm::raw_ostream &OS, const T &V, ASTContext &, QualType) {
+ OS << V;
+}
+
+template <>
+void print(llvm::raw_ostream &OS, const Pointer &P, ASTContext &Ctx,
+ QualType Ty) {
+ if (P.isZero()) {
+ OS << "nullptr";
+ return;
+ }
+
+ auto printDesc = [&OS, &Ctx](Descriptor *Desc) {
+ if (auto *D = Desc->asDecl()) {
+ // Subfields or named values.
+ if (auto *VD = dyn_cast<ValueDecl>(D)) {
+ OS << *VD;
+ return;
+ }
+ // Base classes.
+ if (isa<RecordDecl>(D)) {
+ return;
+ }
+ }
+ // Temporary expression.
+ if (auto *E = Desc->asExpr()) {
+ E->printPretty(OS, nullptr, Ctx.getPrintingPolicy());
+ return;
+ }
+ llvm_unreachable("Invalid descriptor type");
+ };
+
+ if (!Ty->isReferenceType())
+ OS << "&";
+ llvm::SmallVector<Pointer, 2> Levels;
+ for (Pointer F = P; !F.isRoot(); ) {
+ Levels.push_back(F);
+ F = F.isArrayElement() ? F.getArray().expand() : F.getBase();
+ }
+
+ printDesc(P.getDeclDesc());
+ for (auto It = Levels.rbegin(); It != Levels.rend(); ++It) {
+ if (It->inArray()) {
+ OS << "[" << It->expand().getIndex() << "]";
+ continue;
+ }
+ if (auto Index = It->getIndex()) {
+ OS << " + " << Index;
+ continue;
+ }
+ OS << ".";
+ printDesc(It->getFieldDesc());
+ }
+}
+
+void InterpFrame::describe(llvm::raw_ostream &OS) {
+ const FunctionDecl *F = getCallee();
+ auto *M = dyn_cast<CXXMethodDecl>(F);
+ if (M && M->isInstance() && !isa<CXXConstructorDecl>(F)) {
+ print(OS, This, S.getCtx(), S.getCtx().getRecordType(M->getParent()));
+ OS << "->";
+ }
+ OS << *F << "(";
+ unsigned Off = Func->hasRVO() ? primSize(PT_Ptr) : 0;
+ for (unsigned I = 0, N = F->getNumParams(); I < N; ++I) {
+ QualType Ty = F->getParamDecl(I)->getType();
+
+ PrimType PrimTy;
+ if (llvm::Optional<PrimType> T = S.Ctx.classify(Ty)) {
+ PrimTy = *T;
+ } else {
+ PrimTy = PT_Ptr;
+ }
+
+ TYPE_SWITCH(PrimTy, print(OS, stackRef<T>(Off), S.getCtx(), Ty));
+ Off += align(primSize(PrimTy));
+ if (I + 1 != N)
+ OS << ", ";
+ }
+ OS << ")";
+}
+
+Frame *InterpFrame::getCaller() const {
+ if (Caller->Caller)
+ return Caller;
+ return S.getSplitFrame();
+}
+
+SourceLocation InterpFrame::getCallLocation() const {
+ if (!Caller->Func)
+ return S.getLocation(nullptr, {});
+ return S.getLocation(Caller->Func, RetPC - sizeof(uintptr_t));
+}
+
+const FunctionDecl *InterpFrame::getCallee() const {
+ return Func->getDecl();
+}
+
+Pointer InterpFrame::getLocalPointer(unsigned Offset) {
+ assert(Offset < Func->getFrameSize() && "Invalid local offset.");
+ return Pointer(
+ reinterpret_cast<Block *>(Locals.get() + Offset - sizeof(Block)));
+}
+
+Pointer InterpFrame::getParamPointer(unsigned Off) {
+ // Return the block if it was created previously.
+ auto Pt = Params.find(Off);
+ if (Pt != Params.end()) {
+ return Pointer(reinterpret_cast<Block *>(Pt->second.get()));
+ }
+
+ // Allocate memory to store the parameter and the block metadata.
+ const auto &Desc = Func->getParamDescriptor(Off);
+ size_t BlockSize = sizeof(Block) + Desc.second->getAllocSize();
+ auto Memory = std::make_unique<char[]>(BlockSize);
+ auto *B = new (Memory.get()) Block(Desc.second);
+
+ // Copy the initial value.
+ TYPE_SWITCH(Desc.first, new (B->data()) T(stackRef<T>(Off)));
+
+ // Record the param.
+ Params.insert({Off, std::move(Memory)});
+ return Pointer(B);
+}
+
+SourceInfo InterpFrame::getSource(CodePtr PC) const {
+ return S.getSource(Func, PC);
+}
+
+const Expr *InterpFrame::getExpr(CodePtr PC) const {
+ return S.getExpr(Func, PC);
+}
+
+SourceLocation InterpFrame::getLocation(CodePtr PC) const {
+ return S.getLocation(Func, PC);
+}
+
diff --git a/lib/AST/Interp/InterpFrame.h b/lib/AST/Interp/InterpFrame.h
new file mode 100644
index 000000000000..b8391b0bcf92
--- /dev/null
+++ b/lib/AST/Interp/InterpFrame.h
@@ -0,0 +1,153 @@
+//===--- InterpFrame.h - Call Frame implementation for the VM ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the class storing information about stack frames in the interpreter.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_INTERPFRAME_H
+#define LLVM_CLANG_AST_INTERP_INTERPFRAME_H
+
+#include "Frame.h"
+#include "Pointer.h"
+#include "Program.h"
+#include "State.h"
+#include <cstdint>
+#include <vector>
+
+namespace clang {
+namespace interp {
+class Function;
+class InterpState;
+
+/// Frame storing local variables.
+class InterpFrame final : public Frame {
+public:
+ /// The frame of the previous function.
+ InterpFrame *Caller;
+
+ /// Creates a new frame for a method call.
+ InterpFrame(InterpState &S, Function *Func, InterpFrame *Caller,
+ CodePtr RetPC, Pointer &&This);
+
+ /// Destroys the frame, killing all live pointers to stack slots.
+ ~InterpFrame();
+
+ /// Invokes the destructors for a scope.
+ void destroy(unsigned Idx);
+
+ /// Pops the arguments off the stack.
+ void popArgs();
+
+ /// Describes the frame with arguments for diagnostic purposes.
+ void describe(llvm::raw_ostream &OS);
+
+ /// Returns the parent frame object.
+ Frame *getCaller() const;
+
+ /// Returns the location of the call to the frame.
+ SourceLocation getCallLocation() const;
+
+ /// Returns the caller.
+ const FunctionDecl *getCallee() const;
+
+ /// Returns the current function.
+ Function *getFunction() const { return Func; }
+
+ /// Returns the offset on the stack at which the frame starts.
+ size_t getFrameOffset() const { return FrameOffset; }
+
+ /// Returns the value of a local variable.
+ template <typename T> const T &getLocal(unsigned Offset) {
+ return localRef<T>(Offset);
+ }
+
+ /// Mutates a local variable.
+ template <typename T> void setLocal(unsigned Offset, const T &Value) {
+ localRef<T>(Offset) = Value;
+ }
+
+ /// Returns a pointer to a local variables.
+ Pointer getLocalPointer(unsigned Offset);
+
+ /// Returns the value of an argument.
+ template <typename T> const T &getParam(unsigned Offset) {
+ auto Pt = Params.find(Offset);
+ if (Pt == Params.end()) {
+ return stackRef<T>(Offset);
+ } else {
+ return Pointer(reinterpret_cast<Block *>(Pt->second.get())).deref<T>();
+ }
+ }
+
+ /// Mutates a local copy of a parameter.
+ template <typename T> void setParam(unsigned Offset, const T &Value) {
+ getParamPointer(Offset).deref<T>() = Value;
+ }
+
+ /// Returns a pointer to an argument - lazily creates a block.
+ Pointer getParamPointer(unsigned Offset);
+
+ /// Returns the 'this' pointer.
+ const Pointer &getThis() const { return This; }
+
+ /// Checks if the frame is a root frame - return should quit the interpreter.
+ bool isRoot() const { return !Func; }
+
+ /// Returns the PC of the frame's code start.
+ CodePtr getPC() const { return Func->getCodeBegin(); }
+
+ /// Returns the return address of the frame.
+ CodePtr getRetPC() const { return RetPC; }
+
+ /// Map a location to a source.
+ virtual SourceInfo getSource(CodePtr PC) const;
+ const Expr *getExpr(CodePtr PC) const;
+ SourceLocation getLocation(CodePtr PC) const;
+
+private:
+ /// Returns an original argument from the stack.
+ template <typename T> const T &stackRef(unsigned Offset) {
+ return *reinterpret_cast<const T *>(Args - ArgSize + Offset);
+ }
+
+ /// Returns an offset to a local.
+ template <typename T> T &localRef(unsigned Offset) {
+ return *reinterpret_cast<T *>(Locals.get() + Offset);
+ }
+
+ /// Returns a pointer to a local's block.
+ void *localBlock(unsigned Offset) {
+ return Locals.get() + Offset - sizeof(Block);
+ }
+
+private:
+ /// Reference to the interpreter state.
+ InterpState &S;
+ /// Reference to the function being executed.
+ Function *Func;
+ /// Current object pointer for methods.
+ Pointer This;
+ /// Return address.
+ CodePtr RetPC;
+ /// The size of all the arguments.
+ const unsigned ArgSize;
+ /// Pointer to the arguments in the callee's frame.
+ char *Args = nullptr;
+ /// Fixed, initial storage for known local variables.
+ std::unique_ptr<char[]> Locals;
+ /// Offset on the stack at entry.
+ const size_t FrameOffset;
+ /// Mapping from arg offsets to their argument blocks.
+ llvm::DenseMap<unsigned, std::unique_ptr<char[]>> Params;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/InterpStack.cpp b/lib/AST/Interp/InterpStack.cpp
new file mode 100644
index 000000000000..5c803f3d9424
--- /dev/null
+++ b/lib/AST/Interp/InterpStack.cpp
@@ -0,0 +1,78 @@
+//===--- InterpStack.cpp - Stack implementation for the VM ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <cassert>
+#include <cstdlib>
+#include "InterpStack.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+InterpStack::~InterpStack() {
+ clear();
+}
+
+void InterpStack::clear() {
+ if (Chunk && Chunk->Next)
+ free(Chunk->Next);
+ if (Chunk)
+ free(Chunk);
+ Chunk = nullptr;
+ StackSize = 0;
+}
+
+void *InterpStack::grow(size_t Size) {
+ assert(Size < ChunkSize - sizeof(StackChunk) && "Object too large");
+
+ if (!Chunk || sizeof(StackChunk) + Chunk->size() + Size > ChunkSize) {
+ if (Chunk && Chunk->Next) {
+ Chunk = Chunk->Next;
+ } else {
+ StackChunk *Next = new (malloc(ChunkSize)) StackChunk(Chunk);
+ if (Chunk)
+ Chunk->Next = Next;
+ Chunk = Next;
+ }
+ }
+
+ auto *Object = reinterpret_cast<void *>(Chunk->End);
+ Chunk->End += Size;
+ StackSize += Size;
+ return Object;
+}
+
+void *InterpStack::peek(size_t Size) {
+ assert(Chunk && "Stack is empty!");
+
+ StackChunk *Ptr = Chunk;
+ while (Size > Ptr->size()) {
+ Size -= Ptr->size();
+ Ptr = Ptr->Prev;
+ assert(Ptr && "Offset too large");
+ }
+
+ return reinterpret_cast<void *>(Ptr->End - Size);
+}
+
+void InterpStack::shrink(size_t Size) {
+ assert(Chunk && "Chunk is empty!");
+
+ while (Size > Chunk->size()) {
+ Size -= Chunk->size();
+ if (Chunk->Next) {
+ free(Chunk->Next);
+ Chunk->Next = nullptr;
+ }
+ Chunk->End = Chunk->start();
+ Chunk = Chunk->Prev;
+ assert(Chunk && "Offset too large");
+ }
+
+ Chunk->End -= Size;
+ StackSize -= Size;
+}
diff --git a/lib/AST/Interp/InterpStack.h b/lib/AST/Interp/InterpStack.h
new file mode 100644
index 000000000000..127adb6b8eba
--- /dev/null
+++ b/lib/AST/Interp/InterpStack.h
@@ -0,0 +1,113 @@
+//===--- InterpStack.h - Stack implementation for the VM --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the upwards-growing stack used by the interpreter.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_INTERPSTACK_H
+#define LLVM_CLANG_AST_INTERP_INTERPSTACK_H
+
+#include <memory>
+
+namespace clang {
+namespace interp {
+
+/// Stack frame storing temporaries and parameters.
+class InterpStack final {
+public:
+ InterpStack() {}
+
+ /// Destroys the stack, freeing up storage.
+ ~InterpStack();
+
+ /// Constructs a value in place on the top of the stack.
+ template <typename T, typename... Tys> void push(Tys &&... Args) {
+ new (grow(aligned_size<T>())) T(std::forward<Tys>(Args)...);
+ }
+
+ /// Returns the value from the top of the stack and removes it.
+ template <typename T> T pop() {
+ auto *Ptr = &peek<T>();
+ auto Value = std::move(*Ptr);
+ Ptr->~T();
+ shrink(aligned_size<T>());
+ return Value;
+ }
+
+ /// Discards the top value from the stack.
+ template <typename T> void discard() {
+ auto *Ptr = &peek<T>();
+ Ptr->~T();
+ shrink(aligned_size<T>());
+ }
+
+ /// Returns a reference to the value on the top of the stack.
+ template <typename T> T &peek() {
+ return *reinterpret_cast<T *>(peek(aligned_size<T>()));
+ }
+
+ /// Returns a pointer to the top object.
+ void *top() { return Chunk ? peek(0) : nullptr; }
+
+ /// Returns the size of the stack in bytes.
+ size_t size() const { return StackSize; }
+
+ /// Clears the stack without calling any destructors.
+ void clear();
+
+private:
+ /// All stack slots are aligned to the native pointer alignment for storage.
+ /// The size of an object is rounded up to a pointer alignment multiple.
+ template <typename T> constexpr size_t aligned_size() const {
+ constexpr size_t PtrAlign = alignof(void *);
+ return ((sizeof(T) + PtrAlign - 1) / PtrAlign) * PtrAlign;
+ }
+
+ /// Grows the stack to accomodate a value and returns a pointer to it.
+ void *grow(size_t Size);
+ /// Returns a pointer from the top of the stack.
+ void *peek(size_t Size);
+ /// Shrinks the stack.
+ void shrink(size_t Size);
+
+ /// Allocate stack space in 1Mb chunks.
+ static constexpr size_t ChunkSize = 1024 * 1024;
+
+ /// Metadata for each stack chunk.
+ ///
+ /// The stack is composed of a linked list of chunks. Whenever an allocation
+ /// is out of bounds, a new chunk is linked. When a chunk becomes empty,
+ /// it is not immediately freed: a chunk is deallocated only when the
+ /// predecessor becomes empty.
+ struct StackChunk {
+ StackChunk *Next;
+ StackChunk *Prev;
+ char *End;
+
+ StackChunk(StackChunk *Prev = nullptr)
+ : Next(nullptr), Prev(Prev), End(reinterpret_cast<char *>(this + 1)) {}
+
+ /// Returns the size of the chunk, minus the header.
+ size_t size() { return End - start(); }
+
+ /// Returns a pointer to the start of the data region.
+ char *start() { return reinterpret_cast<char *>(this + 1); }
+ };
+ static_assert(sizeof(StackChunk) < ChunkSize, "Invalid chunk size");
+
+ /// First chunk on the stack.
+ StackChunk *Chunk = nullptr;
+ /// Total size of the stack.
+ size_t StackSize = 0;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/InterpState.cpp b/lib/AST/Interp/InterpState.cpp
new file mode 100644
index 000000000000..25684f3c0939
--- /dev/null
+++ b/lib/AST/Interp/InterpState.cpp
@@ -0,0 +1,74 @@
+//===--- InterpState.cpp - Interpreter for the constexpr VM -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "InterpState.h"
+#include <limits>
+#include "Function.h"
+#include "InterpFrame.h"
+#include "InterpStack.h"
+#include "Opcode.h"
+#include "PrimType.h"
+#include "Program.h"
+#include "State.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+using APSInt = llvm::APSInt;
+
+InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
+ Context &Ctx, SourceMapper *M)
+ : Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), Current(nullptr),
+ CallStackDepth(Parent.getCallStackDepth() + 1) {}
+
+InterpState::~InterpState() {
+ while (Current) {
+ InterpFrame *Next = Current->Caller;
+ delete Current;
+ Current = Next;
+ }
+
+ while (DeadBlocks) {
+ DeadBlock *Next = DeadBlocks->Next;
+ free(DeadBlocks);
+ DeadBlocks = Next;
+ }
+}
+
+Frame *InterpState::getCurrentFrame() {
+ if (Current && Current->Caller) {
+ return Current;
+ } else {
+ return Parent.getCurrentFrame();
+ }
+}
+
+bool InterpState::reportOverflow(const Expr *E, const llvm::APSInt &Value) {
+ QualType Type = E->getType();
+ CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
+ return noteUndefinedBehavior();
+}
+
+void InterpState::deallocate(Block *B) {
+ Descriptor *Desc = B->getDescriptor();
+ if (B->hasPointers()) {
+ size_t Size = B->getSize();
+
+ // Allocate a new block, transferring over pointers.
+ char *Memory = reinterpret_cast<char *>(malloc(sizeof(DeadBlock) + Size));
+ auto *D = new (Memory) DeadBlock(DeadBlocks, B);
+
+ // Move data from one block to another.
+ if (Desc->MoveFn)
+ Desc->MoveFn(B, B->data(), D->data(), Desc);
+ } else {
+ // Free storage, if necessary.
+ if (Desc->DtorFn)
+ Desc->DtorFn(B, B->data(), Desc);
+ }
+}
diff --git a/lib/AST/Interp/InterpState.h b/lib/AST/Interp/InterpState.h
new file mode 100644
index 000000000000..c2209bbcbb92
--- /dev/null
+++ b/lib/AST/Interp/InterpState.h
@@ -0,0 +1,112 @@
+//===--- InterpState.h - Interpreter state for the constexpr VM -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Definition of the interpreter state and entry point.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_INTERPSTATE_H
+#define LLVM_CLANG_AST_INTERP_INTERPSTATE_H
+
+#include "Context.h"
+#include "Function.h"
+#include "InterpStack.h"
+#include "State.h"
+#include "clang/AST/APValue.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/OptionalDiagnostic.h"
+
+namespace clang {
+namespace interp {
+class Context;
+class Function;
+class InterpStack;
+class InterpFrame;
+class SourceMapper;
+
+/// Interpreter context.
+class InterpState final : public State, public SourceMapper {
+public:
+ InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
+ SourceMapper *M = nullptr);
+
+ ~InterpState();
+
+ // Stack frame accessors.
+ Frame *getSplitFrame() { return Parent.getCurrentFrame(); }
+ Frame *getCurrentFrame() override;
+ unsigned getCallStackDepth() override { return CallStackDepth; }
+ const Frame *getBottomFrame() const override {
+ return Parent.getBottomFrame();
+ }
+
+ // Acces objects from the walker context.
+ Expr::EvalStatus &getEvalStatus() const override {
+ return Parent.getEvalStatus();
+ }
+ ASTContext &getCtx() const override { return Parent.getCtx(); }
+
+ // Forward status checks and updates to the walker.
+ bool checkingForUndefinedBehavior() const override {
+ return Parent.checkingForUndefinedBehavior();
+ }
+ bool keepEvaluatingAfterFailure() const override {
+ return Parent.keepEvaluatingAfterFailure();
+ }
+ bool checkingPotentialConstantExpression() const override {
+ return Parent.checkingPotentialConstantExpression();
+ }
+ bool noteUndefinedBehavior() override {
+ return Parent.noteUndefinedBehavior();
+ }
+ bool hasActiveDiagnostic() override { return Parent.hasActiveDiagnostic(); }
+ void setActiveDiagnostic(bool Flag) override {
+ Parent.setActiveDiagnostic(Flag);
+ }
+ void setFoldFailureDiagnostic(bool Flag) override {
+ Parent.setFoldFailureDiagnostic(Flag);
+ }
+ bool hasPriorDiagnostic() override { return Parent.hasPriorDiagnostic(); }
+
+ /// Reports overflow and return true if evaluation should continue.
+ bool reportOverflow(const Expr *E, const llvm::APSInt &Value);
+
+ /// Deallocates a pointer.
+ void deallocate(Block *B);
+
+ /// Delegates source mapping to the mapper.
+ SourceInfo getSource(Function *F, CodePtr PC) const override {
+ return M ? M->getSource(F, PC) : F->getSource(PC);
+ }
+
+private:
+ /// AST Walker state.
+ State &Parent;
+ /// Dead block chain.
+ DeadBlock *DeadBlocks = nullptr;
+ /// Reference to the offset-source mapping.
+ SourceMapper *M;
+
+public:
+ /// Reference to the module containing all bytecode.
+ Program &P;
+ /// Temporary stack.
+ InterpStack &Stk;
+ /// Interpreter Context.
+ Context &Ctx;
+ /// The current frame.
+ InterpFrame *Current = nullptr;
+ /// Call stack depth.
+ unsigned CallStackDepth;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/Opcode.h b/lib/AST/Interp/Opcode.h
new file mode 100644
index 000000000000..d2daa1ea52ac
--- /dev/null
+++ b/lib/AST/Interp/Opcode.h
@@ -0,0 +1,30 @@
+//===--- Opcode.h - Opcodes for the constexpr VM ----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines all opcodes executed by the VM and emitted by the compiler.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_OPCODE_H
+#define LLVM_CLANG_AST_INTERP_OPCODE_H
+
+#include <cstdint>
+
+namespace clang {
+namespace interp {
+
+enum Opcode : uint32_t {
+#define GET_OPCODE_NAMES
+#include "Opcodes.inc"
+#undef GET_OPCODE_NAMES
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/Opcodes.td b/lib/AST/Interp/Opcodes.td
new file mode 100644
index 000000000000..4aba5f5cd83c
--- /dev/null
+++ b/lib/AST/Interp/Opcodes.td
@@ -0,0 +1,422 @@
+//===--- Opcodes.td - Opcode defitions for the constexpr VM -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper file used to generate opcodes, the interpreter and the disassembler.
+//
+//===----------------------------------------------------------------------===//
+
+
+//===----------------------------------------------------------------------===//
+// Types evaluated by the interpreter.
+//===----------------------------------------------------------------------===//
+
+class Type;
+def Bool : Type;
+def Sint8 : Type;
+def Uint8 : Type;
+def Sint16 : Type;
+def Uint16 : Type;
+def Sint32 : Type;
+def Uint32 : Type;
+def Sint64 : Type;
+def Uint64 : Type;
+def Ptr : Type;
+
+//===----------------------------------------------------------------------===//
+// Types transferred to the interpreter.
+//===----------------------------------------------------------------------===//
+
+class ArgType { string Name = ?; }
+def ArgSint8 : ArgType { let Name = "int8_t"; }
+def ArgUint8 : ArgType { let Name = "uint8_t"; }
+def ArgSint16 : ArgType { let Name = "int16_t"; }
+def ArgUint16 : ArgType { let Name = "uint16_t"; }
+def ArgSint32 : ArgType { let Name = "int32_t"; }
+def ArgUint32 : ArgType { let Name = "uint32_t"; }
+def ArgSint64 : ArgType { let Name = "int64_t"; }
+def ArgUint64 : ArgType { let Name = "uint64_t"; }
+def ArgBool : ArgType { let Name = "bool"; }
+
+def ArgFunction : ArgType { let Name = "Function *"; }
+def ArgRecord : ArgType { let Name = "Record *"; }
+
+def ArgSema : ArgType { let Name = "const fltSemantics *"; }
+
+def ArgExpr : ArgType { let Name = "const Expr *"; }
+def ArgFloatingLiteral : ArgType { let Name = "const FloatingLiteral *"; }
+def ArgCXXMethodDecl : ArgType { let Name = "const CXXMethodDecl *"; }
+def ArgFunctionDecl : ArgType { let Name = "const FunctionDecl *"; }
+def ArgRecordDecl : ArgType { let Name = "const RecordDecl *"; }
+def ArgCXXRecordDecl : ArgType { let Name = "const CXXRecordDecl *"; }
+def ArgValueDecl : ArgType { let Name = "const ValueDecl *"; }
+def ArgRecordField : ArgType { let Name = "const Record::Field *"; }
+
+//===----------------------------------------------------------------------===//
+// Classes of types intructions operate on.
+//===----------------------------------------------------------------------===//
+
+class TypeClass {
+ list<Type> Types;
+}
+
+def AluTypeClass : TypeClass {
+ let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
+ Uint32, Sint64, Uint64, Bool];
+}
+
+def PtrTypeClass : TypeClass {
+ let Types = [Ptr];
+}
+
+def AllTypeClass : TypeClass {
+ let Types = !listconcat(AluTypeClass.Types, PtrTypeClass.Types);
+}
+
+def ComparableTypeClass : TypeClass {
+ let Types = !listconcat(AluTypeClass.Types, [Ptr]);
+}
+
+class SingletonTypeClass<Type Ty> : TypeClass {
+ let Types = [Ty];
+}
+
+//===----------------------------------------------------------------------===//
+// Record describing all opcodes.
+//===----------------------------------------------------------------------===//
+
+class Opcode {
+ list<TypeClass> Types = [];
+ list<ArgType> Args = [];
+ string Name = "";
+ bit CanReturn = 0;
+ bit ChangesPC = 0;
+ bit HasCustomLink = 0;
+ bit HasCustomEval = 0;
+ bit HasGroup = 0;
+}
+
+class AluOpcode : Opcode {
+ let Types = [AluTypeClass];
+ let HasGroup = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// Jump opcodes
+//===----------------------------------------------------------------------===//
+
+class JumpOpcode : Opcode {
+ let Args = [ArgSint32];
+ let ChangesPC = 1;
+ let HasCustomEval = 1;
+}
+
+// [] -> []
+def Jmp : JumpOpcode;
+// [Bool] -> [], jumps if true.
+def Jt : JumpOpcode;
+// [Bool] -> [], jumps if false.
+def Jf : JumpOpcode;
+
+//===----------------------------------------------------------------------===//
+// Returns
+//===----------------------------------------------------------------------===//
+
+// [Value] -> []
+def Ret : Opcode {
+ let Types = [AllTypeClass];
+ let ChangesPC = 1;
+ let CanReturn = 1;
+ let HasGroup = 1;
+ let HasCustomEval = 1;
+}
+// [] -> []
+def RetVoid : Opcode {
+ let CanReturn = 1;
+ let ChangesPC = 1;
+ let HasCustomEval = 1;
+}
+// [Value] -> []
+def RetValue : Opcode {
+ let CanReturn = 1;
+ let ChangesPC = 1;
+ let HasCustomEval = 1;
+}
+// [] -> EXIT
+def NoRet : Opcode {}
+
+//===----------------------------------------------------------------------===//
+// Frame management
+//===----------------------------------------------------------------------===//
+
+// [] -> []
+def Destroy : Opcode {
+ let Args = [ArgUint32];
+ let HasCustomEval = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// Constants
+//===----------------------------------------------------------------------===//
+
+class ConstOpcode<Type Ty, ArgType ArgTy> : Opcode {
+ let Types = [SingletonTypeClass<Ty>];
+ let Args = [ArgTy];
+ let Name = "Const";
+}
+
+// [] -> [Integer]
+def ConstSint8 : ConstOpcode<Sint8, ArgSint8>;
+def ConstUint8 : ConstOpcode<Uint8, ArgUint8>;
+def ConstSint16 : ConstOpcode<Sint16, ArgSint16>;
+def ConstUint16 : ConstOpcode<Uint16, ArgUint16>;
+def ConstSint32 : ConstOpcode<Sint32, ArgSint32>;
+def ConstUint32 : ConstOpcode<Uint32, ArgUint32>;
+def ConstSint64 : ConstOpcode<Sint64, ArgSint64>;
+def ConstUint64 : ConstOpcode<Uint64, ArgUint64>;
+def ConstBool : ConstOpcode<Bool, ArgBool>;
+
+// [] -> [Integer]
+def Zero : Opcode {
+ let Types = [AluTypeClass];
+}
+
+// [] -> [Pointer]
+def Null : Opcode {
+ let Types = [PtrTypeClass];
+}
+
+//===----------------------------------------------------------------------===//
+// Pointer generation
+//===----------------------------------------------------------------------===//
+
+// [] -> [Pointer]
+def GetPtrLocal : Opcode {
+ // Offset of local.
+ let Args = [ArgUint32];
+ bit HasCustomEval = 1;
+}
+// [] -> [Pointer]
+def GetPtrParam : Opcode {
+ // Offset of parameter.
+ let Args = [ArgUint32];
+}
+// [] -> [Pointer]
+def GetPtrGlobal : Opcode {
+ // Index of global.
+ let Args = [ArgUint32];
+}
+// [Pointer] -> [Pointer]
+def GetPtrField : Opcode {
+ // Offset of field.
+ let Args = [ArgUint32];
+}
+// [Pointer] -> [Pointer]
+def GetPtrActiveField : Opcode {
+ // Offset of field.
+ let Args = [ArgUint32];
+}
+// [] -> [Pointer]
+def GetPtrActiveThisField : Opcode {
+ // Offset of field.
+ let Args = [ArgUint32];
+}
+// [] -> [Pointer]
+def GetPtrThisField : Opcode {
+ // Offset of field.
+ let Args = [ArgUint32];
+}
+// [Pointer] -> [Pointer]
+def GetPtrBase : Opcode {
+ // Offset of field, which is a base.
+ let Args = [ArgUint32];
+}
+// [Pointer] -> [Pointer]
+def GetPtrVirtBase : Opcode {
+ // RecordDecl of base class.
+ let Args = [ArgRecordDecl];
+}
+// [] -> [Pointer]
+def GetPtrThisBase : Opcode {
+ // Offset of field, which is a base.
+ let Args = [ArgUint32];
+}
+// [] -> [Pointer]
+def GetPtrThisVirtBase : Opcode {
+ // RecordDecl of base class.
+ let Args = [ArgRecordDecl];
+}
+// [] -> [Pointer]
+def This : Opcode;
+
+// [Pointer] -> [Pointer]
+def NarrowPtr : Opcode;
+// [Pointer] -> [Pointer]
+def ExpandPtr : Opcode;
+
+//===----------------------------------------------------------------------===//
+// Direct field accessors
+//===----------------------------------------------------------------------===//
+
+class AccessOpcode : Opcode {
+ let Types = [AllTypeClass];
+ let Args = [ArgUint32];
+ let HasGroup = 1;
+}
+
+class BitFieldOpcode : Opcode {
+ let Types = [AluTypeClass];
+ let Args = [ArgRecordField];
+ let HasGroup = 1;
+}
+
+// [] -> [Pointer]
+def GetLocal : AccessOpcode { let HasCustomEval = 1; }
+// [] -> [Pointer]
+def SetLocal : AccessOpcode { let HasCustomEval = 1; }
+
+// [] -> [Value]
+def GetGlobal : AccessOpcode;
+// [Value] -> []
+def InitGlobal : AccessOpcode;
+// [Value] -> []
+def SetGlobal : AccessOpcode;
+
+// [] -> [Value]
+def GetParam : AccessOpcode;
+// [Value] -> []
+def SetParam : AccessOpcode;
+
+// [Pointer] -> [Pointer, Value]
+def GetField : AccessOpcode;
+// [Pointer] -> [Value]
+def GetFieldPop : AccessOpcode;
+// [] -> [Value]
+def GetThisField : AccessOpcode;
+
+// [Pointer, Value] -> [Pointer]
+def SetField : AccessOpcode;
+// [Value] -> []
+def SetThisField : AccessOpcode;
+
+// [Value] -> []
+def InitThisField : AccessOpcode;
+// [Value] -> []
+def InitThisFieldActive : AccessOpcode;
+// [Value] -> []
+def InitThisBitField : BitFieldOpcode;
+// [Pointer, Value] -> []
+def InitField : AccessOpcode;
+// [Pointer, Value] -> []
+def InitBitField : BitFieldOpcode;
+// [Pointer, Value] -> []
+def InitFieldActive : AccessOpcode;
+
+//===----------------------------------------------------------------------===//
+// Pointer access
+//===----------------------------------------------------------------------===//
+
+class LoadOpcode : Opcode {
+ let Types = [AllTypeClass];
+ let HasGroup = 1;
+}
+
+// [Pointer] -> [Pointer, Value]
+def Load : LoadOpcode {}
+// [Pointer] -> [Value]
+def LoadPop : LoadOpcode {}
+
+class StoreOpcode : Opcode {
+ let Types = [AllTypeClass];
+ let HasGroup = 1;
+}
+
+class StoreBitFieldOpcode : Opcode {
+ let Types = [AluTypeClass];
+ let HasGroup = 1;
+}
+
+// [Pointer, Value] -> [Pointer]
+def Store : StoreOpcode {}
+// [Pointer, Value] -> []
+def StorePop : StoreOpcode {}
+
+// [Pointer, Value] -> [Pointer]
+def StoreBitField : StoreBitFieldOpcode {}
+// [Pointer, Value] -> []
+def StoreBitFieldPop : StoreBitFieldOpcode {}
+
+// [Pointer, Value] -> []
+def InitPop : StoreOpcode {}
+// [Pointer, Value] -> [Pointer]
+def InitElem : Opcode {
+ let Types = [AllTypeClass];
+ let Args = [ArgUint32];
+ let HasGroup = 1;
+}
+// [Pointer, Value] -> []
+def InitElemPop : Opcode {
+ let Types = [AllTypeClass];
+ let Args = [ArgUint32];
+ let HasGroup = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// Pointer arithmetic.
+//===----------------------------------------------------------------------===//
+
+// [Pointer, Integral] -> [Pointer]
+def AddOffset : AluOpcode;
+// [Pointer, Integral] -> [Pointer]
+def SubOffset : AluOpcode;
+
+//===----------------------------------------------------------------------===//
+// Binary operators.
+//===----------------------------------------------------------------------===//
+
+// [Real, Real] -> [Real]
+def Sub : AluOpcode;
+def Add : AluOpcode;
+def Mul : AluOpcode;
+
+//===----------------------------------------------------------------------===//
+// Comparison opcodes.
+//===----------------------------------------------------------------------===//
+
+class EqualityOpcode : Opcode {
+ let Types = [AllTypeClass];
+ let HasGroup = 1;
+}
+
+def EQ : EqualityOpcode;
+def NE : EqualityOpcode;
+
+class ComparisonOpcode : Opcode {
+ let Types = [ComparableTypeClass];
+ let HasGroup = 1;
+}
+
+def LT : ComparisonOpcode;
+def LE : ComparisonOpcode;
+def GT : ComparisonOpcode;
+def GE : ComparisonOpcode;
+
+//===----------------------------------------------------------------------===//
+// Stack management.
+//===----------------------------------------------------------------------===//
+
+// [Value] -> []
+def Pop : Opcode {
+ let Types = [AllTypeClass];
+ let HasGroup = 1;
+}
+
+// [Value] -> [Value, Value]
+def Dup : Opcode {
+ let Types = [AllTypeClass];
+ let HasGroup = 1;
+}
diff --git a/lib/AST/Interp/Pointer.cpp b/lib/AST/Interp/Pointer.cpp
new file mode 100644
index 000000000000..1a10723aaca5
--- /dev/null
+++ b/lib/AST/Interp/Pointer.cpp
@@ -0,0 +1,193 @@
+//===--- Pointer.cpp - Types for the constexpr VM ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Pointer.h"
+#include "Block.h"
+#include "Function.h"
+#include "PrimType.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
+
+Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
+
+Pointer::Pointer(Pointer &&P)
+ : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) {
+ if (Pointee)
+ Pointee->movePointer(&P, this);
+}
+
+Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset)
+ : Pointee(Pointee), Base(Base), Offset(Offset) {
+ assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
+ if (Pointee)
+ Pointee->addPointer(this);
+}
+
+Pointer::~Pointer() {
+ if (Pointee) {
+ Pointee->removePointer(this);
+ Pointee->cleanup();
+ }
+}
+
+void Pointer::operator=(const Pointer &P) {
+ Block *Old = Pointee;
+
+ if (Pointee)
+ Pointee->removePointer(this);
+
+ Offset = P.Offset;
+ Base = P.Base;
+
+ Pointee = P.Pointee;
+ if (Pointee)
+ Pointee->addPointer(this);
+
+ if (Old)
+ Old->cleanup();
+}
+
+void Pointer::operator=(Pointer &&P) {
+ Block *Old = Pointee;
+
+ if (Pointee)
+ Pointee->removePointer(this);
+
+ Offset = P.Offset;
+ Base = P.Base;
+
+ Pointee = P.Pointee;
+ if (Pointee)
+ Pointee->movePointer(&P, this);
+
+ if (Old)
+ Old->cleanup();
+}
+
+APValue Pointer::toAPValue() const {
+ APValue::LValueBase Base;
+ llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
+ CharUnits Offset;
+ bool IsNullPtr;
+ bool IsOnePastEnd;
+
+ if (isZero()) {
+ Base = static_cast<const Expr *>(nullptr);
+ IsNullPtr = true;
+ IsOnePastEnd = false;
+ Offset = CharUnits::Zero();
+ } else {
+ // Build the lvalue base from the block.
+ Descriptor *Desc = getDeclDesc();
+ if (auto *VD = Desc->asValueDecl())
+ Base = VD;
+ else if (auto *E = Desc->asExpr())
+ Base = E;
+ else
+ llvm_unreachable("Invalid allocation type");
+
+ // Not a null pointer.
+ IsNullPtr = false;
+
+ if (isUnknownSizeArray()) {
+ IsOnePastEnd = false;
+ Offset = CharUnits::Zero();
+ } else {
+ // TODO: compute the offset into the object.
+ Offset = CharUnits::Zero();
+
+ // Build the path into the object.
+ Pointer Ptr = *this;
+ while (Ptr.isField()) {
+ if (Ptr.isArrayElement()) {
+ Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
+ Ptr = Ptr.getArray();
+ } else {
+ // TODO: figure out if base is virtual
+ bool IsVirtual = false;
+
+ // Create a path entry for the field.
+ Descriptor *Desc = Ptr.getFieldDesc();
+ if (auto *BaseOrMember = Desc->asDecl()) {
+ Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
+ Ptr = Ptr.getBase();
+ continue;
+ }
+ llvm_unreachable("Invalid field type");
+ }
+ }
+
+ IsOnePastEnd = isOnePastEnd();
+ }
+ }
+
+ return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr);
+}
+
+bool Pointer::isInitialized() const {
+ assert(Pointee && "Cannot check if null pointer was initialized");
+ Descriptor *Desc = getFieldDesc();
+ if (Desc->isPrimitiveArray()) {
+ if (Pointee->IsStatic)
+ return true;
+ // Primitive array field are stored in a bitset.
+ InitMap *Map = getInitMap();
+ if (!Map)
+ return false;
+ if (Map == (InitMap *)-1)
+ return true;
+ return Map->isInitialized(getIndex());
+ } else {
+ // Field has its bit in an inline descriptor.
+ return Base == 0 || getInlineDesc()->IsInitialized;
+ }
+}
+
+void Pointer::initialize() const {
+ assert(Pointee && "Cannot initialize null pointer");
+ Descriptor *Desc = getFieldDesc();
+ if (Desc->isPrimitiveArray()) {
+ if (!Pointee->IsStatic) {
+ // Primitive array initializer.
+ InitMap *&Map = getInitMap();
+ if (Map == (InitMap *)-1)
+ return;
+ if (Map == nullptr)
+ Map = InitMap::allocate(Desc->getNumElems());
+ if (Map->initialize(getIndex())) {
+ free(Map);
+ Map = (InitMap *)-1;
+ }
+ }
+ } else {
+ // Field has its bit in an inline descriptor.
+ assert(Base != 0 && "Only composite fields can be initialised");
+ getInlineDesc()->IsInitialized = true;
+ }
+}
+
+void Pointer::activate() const {
+ // Field has its bit in an inline descriptor.
+ assert(Base != 0 && "Only composite fields can be initialised");
+ getInlineDesc()->IsActive = true;
+}
+
+void Pointer::deactivate() const {
+ // TODO: this only appears in constructors, so nothing to deactivate.
+}
+
+bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
+ return A.Pointee == B.Pointee;
+}
+
+bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
+ return A.Base == B.Base && A.getFieldDesc()->IsArray;
+}
diff --git a/lib/AST/Interp/Pointer.h b/lib/AST/Interp/Pointer.h
new file mode 100644
index 000000000000..b8fa98e24faa
--- /dev/null
+++ b/lib/AST/Interp/Pointer.h
@@ -0,0 +1,353 @@
+//===--- Pointer.h - Types for the constexpr VM -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the classes responsible for pointer tracking.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_POINTER_H
+#define LLVM_CLANG_AST_INTERP_POINTER_H
+
+#include "Block.h"
+#include "Descriptor.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ComparisonCategories.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace interp {
+class Block;
+class DeadBlock;
+class Context;
+class InterpState;
+class Pointer;
+class Function;
+enum PrimType : unsigned;
+
+/// A pointer to a memory block, live or dead.
+///
+/// This object can be allocated into interpreter stack frames. If pointing to
+/// a live block, it is a link in the chain of pointers pointing to the block.
+class Pointer {
+private:
+ static constexpr unsigned PastEndMark = (unsigned)-1;
+ static constexpr unsigned RootPtrMark = (unsigned)-1;
+
+public:
+ Pointer() {}
+ Pointer(Block *B);
+ Pointer(const Pointer &P);
+ Pointer(Pointer &&P);
+ ~Pointer();
+
+ void operator=(const Pointer &P);
+ void operator=(Pointer &&P);
+
+ /// Converts the pointer to an APValue.
+ APValue toAPValue() const;
+
+ /// Offsets a pointer inside an array.
+ Pointer atIndex(unsigned Idx) const {
+ if (Base == RootPtrMark)
+ return Pointer(Pointee, RootPtrMark, getDeclDesc()->getSize());
+ unsigned Off = Idx * elemSize();
+ if (getFieldDesc()->ElemDesc)
+ Off += sizeof(InlineDescriptor);
+ else
+ Off += sizeof(InitMap *);
+ return Pointer(Pointee, Base, Base + Off);
+ }
+
+ /// Creates a pointer to a field.
+ Pointer atField(unsigned Off) const {
+ unsigned Field = Offset + Off;
+ return Pointer(Pointee, Field, Field);
+ }
+
+ /// Restricts the scope of an array element pointer.
+ Pointer narrow() const {
+ // Null pointers cannot be narrowed.
+ if (isZero() || isUnknownSizeArray())
+ return *this;
+
+ // Pointer to an array of base types - enter block.
+ if (Base == RootPtrMark)
+ return Pointer(Pointee, 0, Offset == 0 ? Offset : PastEndMark);
+
+ // Pointer is one past end - magic offset marks that.
+ if (isOnePastEnd())
+ return Pointer(Pointee, Base, PastEndMark);
+
+ // Primitive arrays are a bit special since they do not have inline
+ // descriptors. If Offset != Base, then the pointer already points to
+ // an element and there is nothing to do. Otherwise, the pointer is
+ // adjusted to the first element of the array.
+ if (inPrimitiveArray()) {
+ if (Offset != Base)
+ return *this;
+ return Pointer(Pointee, Base, Offset + sizeof(InitMap *));
+ }
+
+ // Pointer is to a field or array element - enter it.
+ if (Offset != Base)
+ return Pointer(Pointee, Offset, Offset);
+
+ // Enter the first element of an array.
+ if (!getFieldDesc()->isArray())
+ return *this;
+
+ const unsigned NewBase = Base + sizeof(InlineDescriptor);
+ return Pointer(Pointee, NewBase, NewBase);
+ }
+
+ /// Expands a pointer to the containing array, undoing narrowing.
+ Pointer expand() const {
+ if (isElementPastEnd()) {
+ // Revert to an outer one-past-end pointer.
+ unsigned Adjust;
+ if (inPrimitiveArray())
+ Adjust = sizeof(InitMap *);
+ else
+ Adjust = sizeof(InlineDescriptor);
+ return Pointer(Pointee, Base, Base + getSize() + Adjust);
+ }
+
+ // Do not step out of array elements.
+ if (Base != Offset)
+ return *this;
+
+ // If at base, point to an array of base types.
+ if (Base == 0)
+ return Pointer(Pointee, RootPtrMark, 0);
+
+ // Step into the containing array, if inside one.
+ unsigned Next = Base - getInlineDesc()->Offset;
+ Descriptor *Desc = Next == 0 ? getDeclDesc() : getDescriptor(Next)->Desc;
+ if (!Desc->IsArray)
+ return *this;
+ return Pointer(Pointee, Next, Offset);
+ }
+
+ /// Checks if the pointer is null.
+ bool isZero() const { return Pointee == nullptr; }
+ /// Checks if the pointer is live.
+ bool isLive() const { return Pointee && !Pointee->IsDead; }
+ /// Checks if the item is a field in an object.
+ bool isField() const { return Base != 0 && Base != RootPtrMark; }
+
+ /// Accessor for information about the declaration site.
+ Descriptor *getDeclDesc() const { return Pointee->Desc; }
+ SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); }
+
+ /// Returns a pointer to the object of which this pointer is a field.
+ Pointer getBase() const {
+ if (Base == RootPtrMark) {
+ assert(Offset == PastEndMark && "cannot get base of a block");
+ return Pointer(Pointee, Base, 0);
+ }
+ assert(Offset == Base && "not an inner field");
+ unsigned NewBase = Base - getInlineDesc()->Offset;
+ return Pointer(Pointee, NewBase, NewBase);
+ }
+ /// Returns the parent array.
+ Pointer getArray() const {
+ if (Base == RootPtrMark) {
+ assert(Offset != 0 && Offset != PastEndMark && "not an array element");
+ return Pointer(Pointee, Base, 0);
+ }
+ assert(Offset != Base && "not an array element");
+ return Pointer(Pointee, Base, Base);
+ }
+
+ /// Accessors for information about the innermost field.
+ Descriptor *getFieldDesc() const {
+ if (Base == 0 || Base == RootPtrMark)
+ return getDeclDesc();
+ return getInlineDesc()->Desc;
+ }
+
+ /// Returns the type of the innermost field.
+ QualType getType() const { return getFieldDesc()->getType(); }
+
+ /// Returns the element size of the innermost field.
+ size_t elemSize() const {
+ if (Base == RootPtrMark)
+ return getDeclDesc()->getSize();
+ return getFieldDesc()->getElemSize();
+ }
+ /// Returns the total size of the innermost field.
+ size_t getSize() const { return getFieldDesc()->getSize(); }
+
+ /// Returns the offset into an array.
+ unsigned getOffset() const {
+ assert(Offset != PastEndMark && "invalid offset");
+ if (Base == RootPtrMark)
+ return Offset;
+
+ unsigned Adjust = 0;
+ if (Offset != Base) {
+ if (getFieldDesc()->ElemDesc)
+ Adjust = sizeof(InlineDescriptor);
+ else
+ Adjust = sizeof(InitMap *);
+ }
+ return Offset - Base - Adjust;
+ }
+
+ /// Checks if the innermost field is an array.
+ bool inArray() const { return getFieldDesc()->IsArray; }
+ /// Checks if the structure is a primitive array.
+ bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); }
+ /// Checks if the structure is an array of unknown size.
+ bool isUnknownSizeArray() const {
+ return getFieldDesc()->isUnknownSizeArray();
+ }
+ /// Checks if the pointer points to an array.
+ bool isArrayElement() const { return Base != Offset; }
+ /// Pointer points directly to a block.
+ bool isRoot() const {
+ return (Base == 0 || Base == RootPtrMark) && Offset == 0;
+ }
+
+ /// Returns the record descriptor of a class.
+ Record *getRecord() const { return getFieldDesc()->ElemRecord; }
+ /// Returns the field information.
+ const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); }
+
+ /// Checks if the object is a union.
+ bool isUnion() const;
+
+ /// Checks if the storage is extern.
+ bool isExtern() const { return Pointee->isExtern(); }
+ /// Checks if the storage is static.
+ bool isStatic() const { return Pointee->isStatic(); }
+ /// Checks if the storage is temporary.
+ bool isTemporary() const { return Pointee->isTemporary(); }
+ /// Checks if the storage is a static temporary.
+ bool isStaticTemporary() const { return isStatic() && isTemporary(); }
+
+ /// Checks if the field is mutable.
+ bool isMutable() const { return Base != 0 && getInlineDesc()->IsMutable; }
+ /// Checks if an object was initialized.
+ bool isInitialized() const;
+ /// Checks if the object is active.
+ bool isActive() const { return Base == 0 || getInlineDesc()->IsActive; }
+ /// Checks if a structure is a base class.
+ bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }
+
+ /// Checks if an object or a subfield is mutable.
+ bool isConst() const {
+ return Base == 0 ? getDeclDesc()->IsConst : getInlineDesc()->IsConst;
+ }
+
+ /// Returns the declaration ID.
+ llvm::Optional<unsigned> getDeclID() const { return Pointee->getDeclID(); }
+
+ /// Returns the byte offset from the start.
+ unsigned getByteOffset() const {
+ return Offset;
+ }
+
+ /// Returns the number of elements.
+ unsigned getNumElems() const { return getSize() / elemSize(); }
+
+ /// Returns the index into an array.
+ int64_t getIndex() const {
+ if (isElementPastEnd())
+ return 1;
+ if (auto ElemSize = elemSize())
+ return getOffset() / ElemSize;
+ return 0;
+ }
+
+ /// Checks if the index is one past end.
+ bool isOnePastEnd() const {
+ return isElementPastEnd() || getSize() == getOffset();
+ }
+
+ /// Checks if the pointer is an out-of-bounds element pointer.
+ bool isElementPastEnd() const { return Offset == PastEndMark; }
+
+ /// Dereferences the pointer, if it's live.
+ template <typename T> T &deref() const {
+ assert(isLive() && "Invalid pointer");
+ return *reinterpret_cast<T *>(Pointee->data() + Offset);
+ }
+
+ /// Dereferences a primitive element.
+ template <typename T> T &elem(unsigned I) const {
+ return reinterpret_cast<T *>(Pointee->data())[I];
+ }
+
+ /// Initializes a field.
+ void initialize() const;
+ /// Activats a field.
+ void activate() const;
+ /// Deactivates an entire strurcutre.
+ void deactivate() const;
+
+ /// Checks if two pointers are comparable.
+ static bool hasSameBase(const Pointer &A, const Pointer &B);
+ /// Checks if two pointers can be subtracted.
+ static bool hasSameArray(const Pointer &A, const Pointer &B);
+
+ /// Prints the pointer.
+ void print(llvm::raw_ostream &OS) const {
+ OS << "{" << Base << ", " << Offset << ", ";
+ if (Pointee)
+ OS << Pointee->getSize();
+ else
+ OS << "nullptr";
+ OS << "}";
+ }
+
+private:
+ friend class Block;
+ friend class DeadBlock;
+
+ Pointer(Block *Pointee, unsigned Base, unsigned Offset);
+
+ /// Returns the embedded descriptor preceding a field.
+ InlineDescriptor *getInlineDesc() const { return getDescriptor(Base); }
+
+ /// Returns a descriptor at a given offset.
+ InlineDescriptor *getDescriptor(unsigned Offset) const {
+ assert(Offset != 0 && "Not a nested pointer");
+ return reinterpret_cast<InlineDescriptor *>(Pointee->data() + Offset) - 1;
+ }
+
+ /// Returns a reference to the pointer which stores the initialization map.
+ InitMap *&getInitMap() const {
+ return *reinterpret_cast<InitMap **>(Pointee->data() + Base);
+ }
+
+ /// The block the pointer is pointing to.
+ Block *Pointee = nullptr;
+ /// Start of the current subfield.
+ unsigned Base = 0;
+ /// Offset into the block.
+ unsigned Offset = 0;
+
+ /// Previous link in the pointer chain.
+ Pointer *Prev = nullptr;
+ /// Next link in the pointer chain.
+ Pointer *Next = nullptr;
+};
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) {
+ P.print(OS);
+ return OS;
+}
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/PrimType.cpp b/lib/AST/Interp/PrimType.cpp
new file mode 100644
index 000000000000..082bfaf3c207
--- /dev/null
+++ b/lib/AST/Interp/PrimType.cpp
@@ -0,0 +1,23 @@
+//===--- Type.cpp - Types for the constexpr VM ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "PrimType.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+namespace clang {
+namespace interp {
+
+size_t primSize(PrimType Type) {
+ TYPE_SWITCH(Type, return sizeof(T));
+ llvm_unreachable("not a primitive type");
+}
+
+} // namespace interp
+} // namespace clang
diff --git a/lib/AST/Interp/PrimType.h b/lib/AST/Interp/PrimType.h
new file mode 100644
index 000000000000..f5f4f8e5c32d
--- /dev/null
+++ b/lib/AST/Interp/PrimType.h
@@ -0,0 +1,115 @@
+//===--- PrimType.h - Types for the constexpr VM --------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the VM types and helpers operating on types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_TYPE_H
+#define LLVM_CLANG_AST_INTERP_TYPE_H
+
+#include <climits>
+#include <cstddef>
+#include <cstdint>
+#include "Boolean.h"
+#include "Integral.h"
+#include "Pointer.h"
+
+namespace clang {
+namespace interp {
+
+/// Enumeration of the primitive types of the VM.
+enum PrimType : unsigned {
+ PT_Sint8,
+ PT_Uint8,
+ PT_Sint16,
+ PT_Uint16,
+ PT_Sint32,
+ PT_Uint32,
+ PT_Sint64,
+ PT_Uint64,
+ PT_Bool,
+ PT_Ptr,
+};
+
+/// Mapping from primitive types to their representation.
+template <PrimType T> struct PrimConv;
+template <> struct PrimConv<PT_Sint8> { using T = Integral<8, true>; };
+template <> struct PrimConv<PT_Uint8> { using T = Integral<8, false>; };
+template <> struct PrimConv<PT_Sint16> { using T = Integral<16, true>; };
+template <> struct PrimConv<PT_Uint16> { using T = Integral<16, false>; };
+template <> struct PrimConv<PT_Sint32> { using T = Integral<32, true>; };
+template <> struct PrimConv<PT_Uint32> { using T = Integral<32, false>; };
+template <> struct PrimConv<PT_Sint64> { using T = Integral<64, true>; };
+template <> struct PrimConv<PT_Uint64> { using T = Integral<64, false>; };
+template <> struct PrimConv<PT_Bool> { using T = Boolean; };
+template <> struct PrimConv<PT_Ptr> { using T = Pointer; };
+
+/// Returns the size of a primitive type in bytes.
+size_t primSize(PrimType Type);
+
+/// Aligns a size to the pointer alignment.
+constexpr size_t align(size_t Size) {
+ return ((Size + alignof(void *) - 1) / alignof(void *)) * alignof(void *);
+}
+
+inline bool isPrimitiveIntegral(PrimType Type) {
+ switch (Type) {
+ case PT_Bool:
+ case PT_Sint8:
+ case PT_Uint8:
+ case PT_Sint16:
+ case PT_Uint16:
+ case PT_Sint32:
+ case PT_Uint32:
+ case PT_Sint64:
+ case PT_Uint64:
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // namespace interp
+} // namespace clang
+
+/// Helper macro to simplify type switches.
+/// The macro implicitly exposes a type T in the scope of the inner block.
+#define TYPE_SWITCH_CASE(Name, B) \
+ case Name: { using T = PrimConv<Name>::T; do {B;} while(0); break; }
+#define TYPE_SWITCH(Expr, B) \
+ switch (Expr) { \
+ TYPE_SWITCH_CASE(PT_Sint8, B) \
+ TYPE_SWITCH_CASE(PT_Uint8, B) \
+ TYPE_SWITCH_CASE(PT_Sint16, B) \
+ TYPE_SWITCH_CASE(PT_Uint16, B) \
+ TYPE_SWITCH_CASE(PT_Sint32, B) \
+ TYPE_SWITCH_CASE(PT_Uint32, B) \
+ TYPE_SWITCH_CASE(PT_Sint64, B) \
+ TYPE_SWITCH_CASE(PT_Uint64, B) \
+ TYPE_SWITCH_CASE(PT_Bool, B) \
+ TYPE_SWITCH_CASE(PT_Ptr, B) \
+ }
+#define COMPOSITE_TYPE_SWITCH(Expr, B, D) \
+ switch (Expr) { \
+ TYPE_SWITCH_CASE(PT_Ptr, B) \
+ default: do { D; } while(0); break; \
+ }
+#define INT_TYPE_SWITCH(Expr, B) \
+ switch (Expr) { \
+ TYPE_SWITCH_CASE(PT_Sint8, B) \
+ TYPE_SWITCH_CASE(PT_Uint8, B) \
+ TYPE_SWITCH_CASE(PT_Sint16, B) \
+ TYPE_SWITCH_CASE(PT_Uint16, B) \
+ TYPE_SWITCH_CASE(PT_Sint32, B) \
+ TYPE_SWITCH_CASE(PT_Uint32, B) \
+ TYPE_SWITCH_CASE(PT_Sint64, B) \
+ TYPE_SWITCH_CASE(PT_Uint64, B) \
+ default: llvm_unreachable("not an integer"); \
+ }
+#endif
diff --git a/lib/AST/Interp/Program.cpp b/lib/AST/Interp/Program.cpp
new file mode 100644
index 000000000000..fcbab0ea8172
--- /dev/null
+++ b/lib/AST/Interp/Program.cpp
@@ -0,0 +1,364 @@
+//===--- Program.cpp - Bytecode for the constexpr VM ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Program.h"
+#include "ByteCodeStmtGen.h"
+#include "Context.h"
+#include "Function.h"
+#include "Opcode.h"
+#include "PrimType.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+unsigned Program::createGlobalString(const StringLiteral *S) {
+ const size_t CharWidth = S->getCharByteWidth();
+ const size_t BitWidth = CharWidth * Ctx.getCharBit();
+
+ PrimType CharType;
+ switch (CharWidth) {
+ case 1:
+ CharType = PT_Sint8;
+ break;
+ case 2:
+ CharType = PT_Uint16;
+ break;
+ case 4:
+ CharType = PT_Uint32;
+ break;
+ default:
+ llvm_unreachable("unsupported character width");
+ }
+
+ // Create a descriptor for the string.
+ Descriptor *Desc = allocateDescriptor(S, CharType, S->getLength() + 1,
+ /*isConst=*/true,
+ /*isTemporary=*/false,
+ /*isMutable=*/false);
+
+ // Allocate storage for the string.
+ // The byte length does not include the null terminator.
+ unsigned I = Globals.size();
+ unsigned Sz = Desc->getAllocSize();
+ auto *G = new (Allocator, Sz) Global(Desc, /*isStatic=*/true,
+ /*isExtern=*/false);
+ Globals.push_back(G);
+
+ // Construct the string in storage.
+ const Pointer Ptr(G->block());
+ for (unsigned I = 0, N = S->getLength(); I <= N; ++I) {
+ Pointer Field = Ptr.atIndex(I).narrow();
+ const uint32_t CodePoint = I == N ? 0 : S->getCodeUnit(I);
+ switch (CharType) {
+ case PT_Sint8: {
+ using T = PrimConv<PT_Sint8>::T;
+ Field.deref<T>() = T::from(CodePoint, BitWidth);
+ break;
+ }
+ case PT_Uint16: {
+ using T = PrimConv<PT_Uint16>::T;
+ Field.deref<T>() = T::from(CodePoint, BitWidth);
+ break;
+ }
+ case PT_Uint32: {
+ using T = PrimConv<PT_Uint32>::T;
+ Field.deref<T>() = T::from(CodePoint, BitWidth);
+ break;
+ }
+ default:
+ llvm_unreachable("unsupported character type");
+ }
+ }
+ return I;
+}
+
+Pointer Program::getPtrGlobal(unsigned Idx) {
+ assert(Idx < Globals.size());
+ return Pointer(Globals[Idx]->block());
+}
+
+llvm::Optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
+ auto It = GlobalIndices.find(VD);
+ if (It != GlobalIndices.end())
+ return It->second;
+
+ // Find any previous declarations which were aleady evaluated.
+ llvm::Optional<unsigned> Index;
+ for (const Decl *P = VD; P; P = P->getPreviousDecl()) {
+ auto It = GlobalIndices.find(P);
+ if (It != GlobalIndices.end()) {
+ Index = It->second;
+ break;
+ }
+ }
+
+ // Map the decl to the existing index.
+ if (Index) {
+ GlobalIndices[VD] = *Index;
+ return {};
+ }
+
+ return Index;
+}
+
+llvm::Optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD) {
+ if (auto Idx = getGlobal(VD))
+ return Idx;
+
+ if (auto Idx = createGlobal(VD)) {
+ GlobalIndices[VD] = *Idx;
+ return Idx;
+ }
+ return {};
+}
+
+llvm::Optional<unsigned> Program::getOrCreateDummy(const ParmVarDecl *PD) {
+ auto &ASTCtx = Ctx.getASTContext();
+
+ // Create a pointer to an incomplete array of the specified elements.
+ QualType ElemTy = PD->getType()->castAs<PointerType>()->getPointeeType();
+ QualType Ty = ASTCtx.getIncompleteArrayType(ElemTy, ArrayType::Normal, 0);
+
+ // Dedup blocks since they are immutable and pointers cannot be compared.
+ auto It = DummyParams.find(PD);
+ if (It != DummyParams.end())
+ return It->second;
+
+ if (auto Idx = createGlobal(PD, Ty, /*isStatic=*/true, /*isExtern=*/true)) {
+ DummyParams[PD] = *Idx;
+ return Idx;
+ }
+ return {};
+}
+
+llvm::Optional<unsigned> Program::createGlobal(const ValueDecl *VD) {
+ bool IsStatic, IsExtern;
+ if (auto *Var = dyn_cast<VarDecl>(VD)) {
+ IsStatic = !Var->hasLocalStorage();
+ IsExtern = !Var->getAnyInitializer();
+ } else {
+ IsStatic = false;
+ IsExtern = true;
+ }
+ if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern)) {
+ for (const Decl *P = VD; P; P = P->getPreviousDecl())
+ GlobalIndices[P] = *Idx;
+ return *Idx;
+ }
+ return {};
+}
+
+llvm::Optional<unsigned> Program::createGlobal(const Expr *E) {
+ return createGlobal(E, E->getType(), /*isStatic=*/true, /*isExtern=*/false);
+}
+
+llvm::Optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
+ bool IsStatic, bool IsExtern) {
+ // Create a descriptor for the global.
+ Descriptor *Desc;
+ const bool IsConst = Ty.isConstQualified();
+ const bool IsTemporary = D.dyn_cast<const Expr *>();
+ if (auto T = Ctx.classify(Ty)) {
+ Desc = createDescriptor(D, *T, IsConst, IsTemporary);
+ } else {
+ Desc = createDescriptor(D, Ty.getTypePtr(), IsConst, IsTemporary);
+ }
+ if (!Desc)
+ return {};
+
+ // Allocate a block for storage.
+ unsigned I = Globals.size();
+
+ auto *G = new (Allocator, Desc->getAllocSize())
+ Global(getCurrentDecl(), Desc, IsStatic, IsExtern);
+ G->block()->invokeCtor();
+
+ Globals.push_back(G);
+
+ return I;
+}
+
+Function *Program::getFunction(const FunctionDecl *F) {
+ F = F->getDefinition();
+ auto It = Funcs.find(F);
+ return It == Funcs.end() ? nullptr : It->second.get();
+}
+
+llvm::Expected<Function *> Program::getOrCreateFunction(const FunctionDecl *F) {
+ if (Function *Func = getFunction(F)) {
+ return Func;
+ }
+
+ // Try to compile the function if it wasn't compiled yet.
+ if (const FunctionDecl *FD = F->getDefinition())
+ return ByteCodeStmtGen<ByteCodeEmitter>(Ctx, *this).compileFunc(FD);
+
+ // A relocation which traps if not resolved.
+ return nullptr;
+}
+
+Record *Program::getOrCreateRecord(const RecordDecl *RD) {
+ // Use the actual definition as a key.
+ RD = RD->getDefinition();
+ if (!RD)
+ return nullptr;
+
+ // Deduplicate records.
+ auto It = Records.find(RD);
+ if (It != Records.end()) {
+ return It->second;
+ }
+
+ // Number of bytes required by fields and base classes.
+ unsigned Size = 0;
+ // Number of bytes required by virtual base.
+ unsigned VirtSize = 0;
+
+ // Helper to get a base descriptor.
+ auto GetBaseDesc = [this](const RecordDecl *BD, Record *BR) -> Descriptor * {
+ if (!BR)
+ return nullptr;
+ return allocateDescriptor(BD, BR, /*isConst=*/false,
+ /*isTemporary=*/false,
+ /*isMutable=*/false);
+ };
+
+ // Reserve space for base classes.
+ Record::BaseList Bases;
+ Record::VirtualBaseList VirtBases;
+ if (auto *CD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (const CXXBaseSpecifier &Spec : CD->bases()) {
+ if (Spec.isVirtual())
+ continue;
+
+ const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl();
+ Record *BR = getOrCreateRecord(BD);
+ if (Descriptor *Desc = GetBaseDesc(BD, BR)) {
+ Size += align(sizeof(InlineDescriptor));
+ Bases.push_back({BD, Size, Desc, BR});
+ Size += align(BR->getSize());
+ continue;
+ }
+ return nullptr;
+ }
+
+ for (const CXXBaseSpecifier &Spec : CD->vbases()) {
+ const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl();
+ Record *BR = getOrCreateRecord(BD);
+
+ if (Descriptor *Desc = GetBaseDesc(BD, BR)) {
+ VirtSize += align(sizeof(InlineDescriptor));
+ VirtBases.push_back({BD, VirtSize, Desc, BR});
+ VirtSize += align(BR->getSize());
+ continue;
+ }
+ return nullptr;
+ }
+ }
+
+ // Reserve space for fields.
+ Record::FieldList Fields;
+ for (const FieldDecl *FD : RD->fields()) {
+ // Reserve space for the field's descriptor and the offset.
+ Size += align(sizeof(InlineDescriptor));
+
+ // Classify the field and add its metadata.
+ QualType FT = FD->getType();
+ const bool IsConst = FT.isConstQualified();
+ const bool IsMutable = FD->isMutable();
+ Descriptor *Desc;
+ if (llvm::Optional<PrimType> T = Ctx.classify(FT)) {
+ Desc = createDescriptor(FD, *T, IsConst, /*isTemporary=*/false,
+ IsMutable);
+ } else {
+ Desc = createDescriptor(FD, FT.getTypePtr(), IsConst,
+ /*isTemporary=*/false, IsMutable);
+ }
+ if (!Desc)
+ return nullptr;
+ Fields.push_back({FD, Size, Desc});
+ Size += align(Desc->getAllocSize());
+ }
+
+ Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields),
+ std::move(VirtBases), VirtSize, Size);
+ Records.insert({RD, R});
+ return R;
+}
+
+Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
+ bool IsConst, bool IsTemporary,
+ bool IsMutable) {
+ // Classes and structures.
+ if (auto *RT = Ty->getAs<RecordType>()) {
+ if (auto *Record = getOrCreateRecord(RT->getDecl()))
+ return allocateDescriptor(D, Record, IsConst, IsTemporary, IsMutable);
+ }
+
+ // Arrays.
+ if (auto ArrayType = Ty->getAsArrayTypeUnsafe()) {
+ QualType ElemTy = ArrayType->getElementType();
+ // Array of well-known bounds.
+ if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
+ size_t NumElems = CAT->getSize().getZExtValue();
+ if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) {
+ // Arrays of primitives.
+ unsigned ElemSize = primSize(*T);
+ if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) {
+ return {};
+ }
+ return allocateDescriptor(D, *T, NumElems, IsConst, IsTemporary,
+ IsMutable);
+ } else {
+ // Arrays of composites. In this case, the array is a list of pointers,
+ // followed by the actual elements.
+ Descriptor *Desc =
+ createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
+ if (!Desc)
+ return nullptr;
+ InterpSize ElemSize = Desc->getAllocSize() + sizeof(InlineDescriptor);
+ if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems)
+ return {};
+ return allocateDescriptor(D, Desc, NumElems, IsConst, IsTemporary,
+ IsMutable);
+ }
+ }
+
+ // Array of unknown bounds - cannot be accessed and pointer arithmetic
+ // is forbidden on pointers to such objects.
+ if (isa<IncompleteArrayType>(ArrayType)) {
+ if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) {
+ return allocateDescriptor(D, *T, IsTemporary,
+ Descriptor::UnknownSize{});
+ } else {
+ Descriptor *Desc =
+ createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
+ if (!Desc)
+ return nullptr;
+ return allocateDescriptor(D, Desc, IsTemporary,
+ Descriptor::UnknownSize{});
+ }
+ }
+ }
+
+ // Atomic types.
+ if (auto *AT = Ty->getAs<AtomicType>()) {
+ const Type *InnerTy = AT->getValueType().getTypePtr();
+ return createDescriptor(D, InnerTy, IsConst, IsTemporary, IsMutable);
+ }
+
+ // Complex types - represented as arrays of elements.
+ if (auto *CT = Ty->getAs<ComplexType>()) {
+ PrimType ElemTy = *Ctx.classify(CT->getElementType());
+ return allocateDescriptor(D, ElemTy, 2, IsConst, IsTemporary, IsMutable);
+ }
+
+ return nullptr;
+}
diff --git a/lib/AST/Interp/Program.h b/lib/AST/Interp/Program.h
new file mode 100644
index 000000000000..5f0012db9b3f
--- /dev/null
+++ b/lib/AST/Interp/Program.h
@@ -0,0 +1,220 @@
+//===--- Program.h - Bytecode for the constexpr VM --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a program which organises and links multiple bytecode functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_PROGRAM_H
+#define LLVM_CLANG_AST_INTERP_PROGRAM_H
+
+#include <map>
+#include <vector>
+#include "Function.h"
+#include "Pointer.h"
+#include "PrimType.h"
+#include "Record.h"
+#include "Source.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+
+namespace clang {
+class RecordDecl;
+class Expr;
+class FunctionDecl;
+class Stmt;
+class StringLiteral;
+class VarDecl;
+
+namespace interp {
+class Context;
+class State;
+class Record;
+class Scope;
+
+/// The program contains and links the bytecode for all functions.
+class Program {
+public:
+ Program(Context &Ctx) : Ctx(Ctx) {}
+
+ /// Emits a string literal among global data.
+ unsigned createGlobalString(const StringLiteral *S);
+
+ /// Returns a pointer to a global.
+ Pointer getPtrGlobal(unsigned Idx);
+
+ /// Returns the value of a global.
+ Block *getGlobal(unsigned Idx) {
+ assert(Idx < Globals.size());
+ return Globals[Idx]->block();
+ }
+
+ /// Finds a global's index.
+ llvm::Optional<unsigned> getGlobal(const ValueDecl *VD);
+
+ /// Returns or creates a global an creates an index to it.
+ llvm::Optional<unsigned> getOrCreateGlobal(const ValueDecl *VD);
+
+ /// Returns or creates a dummy value for parameters.
+ llvm::Optional<unsigned> getOrCreateDummy(const ParmVarDecl *PD);
+
+ /// Creates a global and returns its index.
+ llvm::Optional<unsigned> createGlobal(const ValueDecl *VD);
+
+ /// Creates a global from a lifetime-extended temporary.
+ llvm::Optional<unsigned> createGlobal(const Expr *E);
+
+ /// Creates a new function from a code range.
+ template <typename... Ts>
+ Function *createFunction(const FunctionDecl *Def, Ts &&... Args) {
+ auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...);
+ Funcs.insert({Def, std::unique_ptr<Function>(Func)});
+ return Func;
+ }
+ /// Creates an anonymous function.
+ template <typename... Ts>
+ Function *createFunction(Ts &&... Args) {
+ auto *Func = new Function(*this, std::forward<Ts>(Args)...);
+ AnonFuncs.emplace_back(Func);
+ return Func;
+ }
+
+ /// Returns a function.
+ Function *getFunction(const FunctionDecl *F);
+
+ /// Returns a pointer to a function if it exists and can be compiled.
+ /// If a function couldn't be compiled, an error is returned.
+ /// If a function was not yet defined, a null pointer is returned.
+ llvm::Expected<Function *> getOrCreateFunction(const FunctionDecl *F);
+
+ /// Returns a record or creates one if it does not exist.
+ Record *getOrCreateRecord(const RecordDecl *RD);
+
+ /// Creates a descriptor for a primitive type.
+ Descriptor *createDescriptor(const DeclTy &D, PrimType Type,
+ bool IsConst = false,
+ bool IsTemporary = false,
+ bool IsMutable = false) {
+ return allocateDescriptor(D, Type, IsConst, IsTemporary, IsMutable);
+ }
+
+ /// Creates a descriptor for a composite type.
+ Descriptor *createDescriptor(const DeclTy &D, const Type *Ty,
+ bool IsConst = false, bool IsTemporary = false,
+ bool IsMutable = false);
+
+ /// Context to manage declaration lifetimes.
+ class DeclScope {
+ public:
+ DeclScope(Program &P, const VarDecl *VD) : P(P) { P.startDeclaration(VD); }
+ ~DeclScope() { P.endDeclaration(); }
+
+ private:
+ Program &P;
+ };
+
+ /// Returns the current declaration ID.
+ llvm::Optional<unsigned> getCurrentDecl() const {
+ if (CurrentDeclaration == NoDeclaration)
+ return llvm::Optional<unsigned>{};
+ return LastDeclaration;
+ }
+
+private:
+ friend class DeclScope;
+
+ llvm::Optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
+ bool IsStatic, bool IsExtern);
+
+ /// Reference to the VM context.
+ Context &Ctx;
+ /// Mapping from decls to cached bytecode functions.
+ llvm::DenseMap<const FunctionDecl *, std::unique_ptr<Function>> Funcs;
+ /// List of anonymous functions.
+ std::vector<std::unique_ptr<Function>> AnonFuncs;
+
+ /// Function relocation locations.
+ llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs;
+
+ /// Custom allocator for global storage.
+ using PoolAllocTy = llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator>;
+
+ /// Descriptor + storage for a global object.
+ ///
+ /// Global objects never go out of scope, thus they do not track pointers.
+ class Global {
+ public:
+ /// Create a global descriptor for string literals.
+ template <typename... Tys>
+ Global(Tys... Args) : B(std::forward<Tys>(Args)...) {}
+
+ /// Allocates the global in the pool, reserving storate for data.
+ void *operator new(size_t Meta, PoolAllocTy &Alloc, size_t Data) {
+ return Alloc.Allocate(Meta + Data, alignof(void *));
+ }
+
+ /// Return a pointer to the data.
+ char *data() { return B.data(); }
+ /// Return a pointer to the block.
+ Block *block() { return &B; }
+
+ private:
+ /// Required metadata - does not actually track pointers.
+ Block B;
+ };
+
+ /// Allocator for globals.
+ PoolAllocTy Allocator;
+
+ /// Global objects.
+ std::vector<Global *> Globals;
+ /// Cached global indices.
+ llvm::DenseMap<const void *, unsigned> GlobalIndices;
+
+ /// Mapping from decls to record metadata.
+ llvm::DenseMap<const RecordDecl *, Record *> Records;
+
+ /// Dummy parameter to generate pointers from.
+ llvm::DenseMap<const ParmVarDecl *, unsigned> DummyParams;
+
+ /// Creates a new descriptor.
+ template <typename... Ts>
+ Descriptor *allocateDescriptor(Ts &&... Args) {
+ return new (Allocator) Descriptor(std::forward<Ts>(Args)...);
+ }
+
+ /// No declaration ID.
+ static constexpr unsigned NoDeclaration = (unsigned)-1;
+ /// Last declaration ID.
+ unsigned LastDeclaration = 0;
+ /// Current declaration ID.
+ unsigned CurrentDeclaration = NoDeclaration;
+
+ /// Starts evaluating a declaration.
+ void startDeclaration(const VarDecl *Decl) {
+ LastDeclaration += 1;
+ CurrentDeclaration = LastDeclaration;
+ }
+
+ /// Ends a global declaration.
+ void endDeclaration() {
+ CurrentDeclaration = NoDeclaration;
+ }
+
+public:
+ /// Dumps the disassembled bytecode to \c llvm::errs().
+ void dump() const;
+ void dump(llvm::raw_ostream &OS) const;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/Record.cpp b/lib/AST/Interp/Record.cpp
new file mode 100644
index 000000000000..f440c4705051
--- /dev/null
+++ b/lib/AST/Interp/Record.cpp
@@ -0,0 +1,46 @@
+//===--- Record.cpp - struct and class metadata for the VM ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Record.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+Record::Record(const RecordDecl *Decl, BaseList &&SrcBases,
+ FieldList &&SrcFields, VirtualBaseList &&SrcVirtualBases,
+ unsigned VirtualSize, unsigned BaseSize)
+ : Decl(Decl), Bases(std::move(SrcBases)), Fields(std::move(SrcFields)),
+ BaseSize(BaseSize), VirtualSize(VirtualSize) {
+ for (Base &V : SrcVirtualBases)
+ VirtualBases.push_back({ V.Decl, V.Offset + BaseSize, V.Desc, V.R });
+
+ for (Base &B : Bases)
+ BaseMap[B.Decl] = &B;
+ for (Field &F : Fields)
+ FieldMap[F.Decl] = &F;
+ for (Base &V : VirtualBases)
+ VirtualBaseMap[V.Decl] = &V;
+}
+
+const Record::Field *Record::getField(const FieldDecl *FD) const {
+ auto It = FieldMap.find(FD);
+ assert(It != FieldMap.end() && "Missing field");
+ return It->second;
+}
+
+const Record::Base *Record::getBase(const RecordDecl *FD) const {
+ auto It = BaseMap.find(FD);
+ assert(It != BaseMap.end() && "Missing base");
+ return It->second;
+}
+
+const Record::Base *Record::getVirtualBase(const RecordDecl *FD) const {
+ auto It = VirtualBaseMap.find(FD);
+ assert(It != VirtualBaseMap.end() && "Missing virtual base");
+ return It->second;
+}
diff --git a/lib/AST/Interp/Record.h b/lib/AST/Interp/Record.h
new file mode 100644
index 000000000000..9cdee9003752
--- /dev/null
+++ b/lib/AST/Interp/Record.h
@@ -0,0 +1,121 @@
+//===--- Record.h - struct and class metadata for the VM --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// A record is part of a program to describe the layout and methods of a struct.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_RECORD_H
+#define LLVM_CLANG_AST_INTERP_RECORD_H
+
+#include "Pointer.h"
+
+namespace clang {
+namespace interp {
+class Program;
+
+/// Structure/Class descriptor.
+class Record {
+public:
+ /// Describes a record field.
+ struct Field {
+ const FieldDecl *Decl;
+ unsigned Offset;
+ Descriptor *Desc;
+ };
+
+ /// Describes a base class.
+ struct Base {
+ const RecordDecl *Decl;
+ unsigned Offset;
+ Descriptor *Desc;
+ Record *R;
+ };
+
+ /// Mapping from identifiers to field descriptors.
+ using FieldList = llvm::SmallVector<Field, 8>;
+ /// Mapping from identifiers to base classes.
+ using BaseList = llvm::SmallVector<Base, 8>;
+ /// List of virtual base classes.
+ using VirtualBaseList = llvm::SmallVector<Base, 2>;
+
+public:
+ /// Returns the underlying declaration.
+ const RecordDecl *getDecl() const { return Decl; }
+ /// Checks if the record is a union.
+ bool isUnion() const { return getDecl()->isUnion(); }
+ /// Returns the size of the record.
+ unsigned getSize() const { return BaseSize; }
+ /// Returns the full size of the record, including records.
+ unsigned getFullSize() const { return BaseSize + VirtualSize; }
+ /// Returns a field.
+ const Field *getField(const FieldDecl *FD) const;
+ /// Returns a base descriptor.
+ const Base *getBase(const RecordDecl *FD) const;
+ /// Returns a virtual base descriptor.
+ const Base *getVirtualBase(const RecordDecl *RD) const;
+
+ using const_field_iter = FieldList::const_iterator;
+ llvm::iterator_range<const_field_iter> fields() const {
+ return llvm::make_range(Fields.begin(), Fields.end());
+ }
+
+ unsigned getNumFields() { return Fields.size(); }
+ Field *getField(unsigned I) { return &Fields[I]; }
+
+ using const_base_iter = BaseList::const_iterator;
+ llvm::iterator_range<const_base_iter> bases() const {
+ return llvm::make_range(Bases.begin(), Bases.end());
+ }
+
+ unsigned getNumBases() { return Bases.size(); }
+ Base *getBase(unsigned I) { return &Bases[I]; }
+
+ using const_virtual_iter = VirtualBaseList::const_iterator;
+ llvm::iterator_range<const_virtual_iter> virtual_bases() const {
+ return llvm::make_range(VirtualBases.begin(), VirtualBases.end());
+ }
+
+ unsigned getNumVirtualBases() { return VirtualBases.size(); }
+ Base *getVirtualBase(unsigned I) { return &VirtualBases[I]; }
+
+private:
+ /// Constructor used by Program to create record descriptors.
+ Record(const RecordDecl *, BaseList &&Bases, FieldList &&Fields,
+ VirtualBaseList &&VirtualBases, unsigned VirtualSize,
+ unsigned BaseSize);
+
+private:
+ friend class Program;
+
+ /// Original declaration.
+ const RecordDecl *Decl;
+ /// List of all base classes.
+ BaseList Bases;
+ /// List of all the fields in the record.
+ FieldList Fields;
+ /// List o fall virtual bases.
+ VirtualBaseList VirtualBases;
+
+ /// Mapping from declarations to bases.
+ llvm::DenseMap<const RecordDecl *, Base *> BaseMap;
+ /// Mapping from field identifiers to descriptors.
+ llvm::DenseMap<const FieldDecl *, Field *> FieldMap;
+ /// Mapping from declarations to virtual bases.
+ llvm::DenseMap<const RecordDecl *, Base *> VirtualBaseMap;
+ /// Mapping from
+ /// Size of the structure.
+ unsigned BaseSize;
+ /// Size of all virtual bases.
+ unsigned VirtualSize;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/Source.cpp b/lib/AST/Interp/Source.cpp
new file mode 100644
index 000000000000..4bec87812638
--- /dev/null
+++ b/lib/AST/Interp/Source.cpp
@@ -0,0 +1,39 @@
+//===--- Source.cpp - Source expression tracking ----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Source.h"
+#include "clang/AST/Expr.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+SourceLocation SourceInfo::getLoc() const {
+ if (const Expr *E = asExpr())
+ return E->getExprLoc();
+ if (const Stmt *S = asStmt())
+ return S->getBeginLoc();
+ if (const Decl *D = asDecl())
+ return D->getBeginLoc();
+ return SourceLocation();
+}
+
+const Expr *SourceInfo::asExpr() const {
+ if (auto *S = Source.dyn_cast<const Stmt *>())
+ return dyn_cast<Expr>(S);
+ return nullptr;
+}
+
+const Expr *SourceMapper::getExpr(Function *F, CodePtr PC) const {
+ if (const Expr *E = getSource(F, PC).asExpr())
+ return E;
+ llvm::report_fatal_error("missing source expression");
+}
+
+SourceLocation SourceMapper::getLocation(Function *F, CodePtr PC) const {
+ return getSource(F, PC).getLoc();
+}
diff --git a/lib/AST/Interp/Source.h b/lib/AST/Interp/Source.h
new file mode 100644
index 000000000000..e591c3399d7c
--- /dev/null
+++ b/lib/AST/Interp/Source.h
@@ -0,0 +1,118 @@
+//===--- Source.h - Source location provider for the VM --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a program which organises and links multiple bytecode functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_SOURCE_H
+#define LLVM_CLANG_AST_INTERP_SOURCE_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Stmt.h"
+#include "llvm/Support/Endian.h"
+
+namespace clang {
+namespace interp {
+class Function;
+
+/// Pointer into the code segment.
+class CodePtr {
+public:
+ CodePtr() : Ptr(nullptr) {}
+
+ CodePtr &operator+=(int32_t Offset) {
+ Ptr += Offset;
+ return *this;
+ }
+
+ int32_t operator-(const CodePtr &RHS) const {
+ assert(Ptr != nullptr && RHS.Ptr != nullptr && "Invalid code pointer");
+ return Ptr - RHS.Ptr;
+ }
+
+ CodePtr operator-(size_t RHS) const {
+ assert(Ptr != nullptr && "Invalid code pointer");
+ return CodePtr(Ptr - RHS);
+ }
+
+ bool operator!=(const CodePtr &RHS) const { return Ptr != RHS.Ptr; }
+
+ /// Reads data and advances the pointer.
+ template <typename T> T read() {
+ T Value = ReadHelper<T>(Ptr);
+ Ptr += sizeof(T);
+ return Value;
+ }
+
+private:
+ /// Constructor used by Function to generate pointers.
+ CodePtr(const char *Ptr) : Ptr(Ptr) {}
+
+ /// Helper to decode a value or a pointer.
+ template <typename T>
+ static typename std::enable_if<!std::is_pointer<T>::value, T>::type
+ ReadHelper(const char *Ptr) {
+ using namespace llvm::support;
+ return endian::read<T, endianness::native, 1>(Ptr);
+ }
+
+ template <typename T>
+ static typename std::enable_if<std::is_pointer<T>::value, T>::type
+ ReadHelper(const char *Ptr) {
+ using namespace llvm::support;
+ auto Punned = endian::read<uintptr_t, endianness::native, 1>(Ptr);
+ return reinterpret_cast<T>(Punned);
+ }
+
+private:
+ friend class Function;
+
+ /// Pointer into the code owned by a function.
+ const char *Ptr;
+};
+
+/// Describes the statement/declaration an opcode was generated from.
+class SourceInfo {
+public:
+ SourceInfo() {}
+ SourceInfo(const Stmt *E) : Source(E) {}
+ SourceInfo(const Decl *D) : Source(D) {}
+
+ SourceLocation getLoc() const;
+
+ const Stmt *asStmt() const { return Source.dyn_cast<const Stmt *>(); }
+ const Decl *asDecl() const { return Source.dyn_cast<const Decl *>(); }
+ const Expr *asExpr() const;
+
+ operator bool() const { return !Source.isNull(); }
+
+private:
+ llvm::PointerUnion<const Decl *, const Stmt *> Source;
+};
+
+using SourceMap = std::vector<std::pair<unsigned, SourceInfo>>;
+
+/// Interface for classes which map locations to sources.
+class SourceMapper {
+public:
+ virtual ~SourceMapper() {}
+
+ /// Returns source information for a given PC in a function.
+ virtual SourceInfo getSource(Function *F, CodePtr PC) const = 0;
+
+ /// Returns the expression if an opcode belongs to one, null otherwise.
+ const Expr *getExpr(Function *F, CodePtr PC) const;
+ /// Returns the location from which an opcode originates.
+ SourceLocation getLocation(Function *F, CodePtr PC) const;
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/Interp/State.cpp b/lib/AST/Interp/State.cpp
new file mode 100644
index 000000000000..692cc2e8d69b
--- /dev/null
+++ b/lib/AST/Interp/State.cpp
@@ -0,0 +1,158 @@
+//===--- State.cpp - State chain for the VM and AST Walker ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "State.h"
+#include "Frame.h"
+#include "Program.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/CXXInheritance.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+State::~State() {}
+
+OptionalDiagnostic State::FFDiag(SourceLocation Loc, diag::kind DiagId,
+ unsigned ExtraNotes) {
+ return diag(Loc, DiagId, ExtraNotes, false);
+}
+
+OptionalDiagnostic State::FFDiag(const Expr *E, diag::kind DiagId,
+ unsigned ExtraNotes) {
+ if (getEvalStatus().Diag)
+ return diag(E->getExprLoc(), DiagId, ExtraNotes, false);
+ setActiveDiagnostic(false);
+ return OptionalDiagnostic();
+}
+
+OptionalDiagnostic State::FFDiag(const SourceInfo &SI, diag::kind DiagId,
+ unsigned ExtraNotes) {
+ if (getEvalStatus().Diag)
+ return diag(SI.getLoc(), DiagId, ExtraNotes, false);
+ setActiveDiagnostic(false);
+ return OptionalDiagnostic();
+}
+
+OptionalDiagnostic State::CCEDiag(SourceLocation Loc, diag::kind DiagId,
+ unsigned ExtraNotes) {
+ // Don't override a previous diagnostic. Don't bother collecting
+ // diagnostics if we're evaluating for overflow.
+ if (!getEvalStatus().Diag || !getEvalStatus().Diag->empty()) {
+ setActiveDiagnostic(false);
+ return OptionalDiagnostic();
+ }
+ return diag(Loc, DiagId, ExtraNotes, true);
+}
+
+OptionalDiagnostic State::CCEDiag(const Expr *E, diag::kind DiagId,
+ unsigned ExtraNotes) {
+ return CCEDiag(E->getExprLoc(), DiagId, ExtraNotes);
+}
+
+OptionalDiagnostic State::CCEDiag(const SourceInfo &SI, diag::kind DiagId,
+ unsigned ExtraNotes) {
+ return CCEDiag(SI.getLoc(), DiagId, ExtraNotes);
+}
+
+OptionalDiagnostic State::Note(SourceLocation Loc, diag::kind DiagId) {
+ if (!hasActiveDiagnostic())
+ return OptionalDiagnostic();
+ return OptionalDiagnostic(&addDiag(Loc, DiagId));
+}
+
+void State::addNotes(ArrayRef<PartialDiagnosticAt> Diags) {
+ if (hasActiveDiagnostic()) {
+ getEvalStatus().Diag->insert(getEvalStatus().Diag->end(), Diags.begin(),
+ Diags.end());
+ }
+}
+
+DiagnosticBuilder State::report(SourceLocation Loc, diag::kind DiagId) {
+ return getCtx().getDiagnostics().Report(Loc, DiagId);
+}
+
+/// Add a diagnostic to the diagnostics list.
+PartialDiagnostic &State::addDiag(SourceLocation Loc, diag::kind DiagId) {
+ PartialDiagnostic PD(DiagId, getCtx().getDiagAllocator());
+ getEvalStatus().Diag->push_back(std::make_pair(Loc, PD));
+ return getEvalStatus().Diag->back().second;
+}
+
+OptionalDiagnostic State::diag(SourceLocation Loc, diag::kind DiagId,
+ unsigned ExtraNotes, bool IsCCEDiag) {
+ Expr::EvalStatus &EvalStatus = getEvalStatus();
+ if (EvalStatus.Diag) {
+ if (hasPriorDiagnostic()) {
+ return OptionalDiagnostic();
+ }
+
+ unsigned CallStackNotes = getCallStackDepth() - 1;
+ unsigned Limit = getCtx().getDiagnostics().getConstexprBacktraceLimit();
+ if (Limit)
+ CallStackNotes = std::min(CallStackNotes, Limit + 1);
+ if (checkingPotentialConstantExpression())
+ CallStackNotes = 0;
+
+ setActiveDiagnostic(true);
+ setFoldFailureDiagnostic(!IsCCEDiag);
+ EvalStatus.Diag->clear();
+ EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes);
+ addDiag(Loc, DiagId);
+ if (!checkingPotentialConstantExpression()) {
+ addCallStack(Limit);
+ }
+ return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second);
+ }
+ setActiveDiagnostic(false);
+ return OptionalDiagnostic();
+}
+
+const LangOptions &State::getLangOpts() const { return getCtx().getLangOpts(); }
+
+void State::addCallStack(unsigned Limit) {
+ // Determine which calls to skip, if any.
+ unsigned ActiveCalls = getCallStackDepth() - 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;
+ Frame *Top = getCurrentFrame();
+ const Frame *Bottom = getBottomFrame();
+ for (Frame *F = Top; F != Bottom; F = F->getCaller(), ++CallIdx) {
+ SourceLocation CallLocation = F->getCallLocation();
+
+ // Skip this call?
+ if (CallIdx >= SkipStart && CallIdx < SkipEnd) {
+ if (CallIdx == SkipStart) {
+ // Note that we're skipping calls.
+ addDiag(CallLocation, diag::note_constexpr_calls_suppressed)
+ << unsigned(ActiveCalls - Limit);
+ }
+ continue;
+ }
+
+ // Use a different note for an inheriting constructor, because from the
+ // user's perspective it's not really a function at all.
+ if (auto *CD = dyn_cast_or_null<CXXConstructorDecl>(F->getCallee())) {
+ if (CD->isInheritingConstructor()) {
+ addDiag(CallLocation, diag::note_constexpr_inherited_ctor_call_here)
+ << CD->getParent();
+ continue;
+ }
+ }
+
+ SmallVector<char, 128> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ F->describe(Out);
+ addDiag(CallLocation, diag::note_constexpr_call_here) << Out.str();
+ }
+}
diff --git a/lib/AST/Interp/State.h b/lib/AST/Interp/State.h
new file mode 100644
index 000000000000..d9a645a3eb3e
--- /dev/null
+++ b/lib/AST/Interp/State.h
@@ -0,0 +1,133 @@
+//===--- State.h - State chain for the VM and AST Walker --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the base class of the interpreter and evaluator state.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_STATE_H
+#define LLVM_CLANG_AST_INTERP_STATE_H
+
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/OptionalDiagnostic.h"
+
+namespace clang {
+
+/// Kinds of access we can perform on an object, for diagnostics. Note that
+/// we consider a member function call to be a kind of access, even though
+/// it is not formally an access of the object, because it has (largely) the
+/// same set of semantic restrictions.
+enum AccessKinds {
+ AK_Read,
+ AK_ReadObjectRepresentation,
+ AK_Assign,
+ AK_Increment,
+ AK_Decrement,
+ AK_MemberCall,
+ AK_DynamicCast,
+ AK_TypeId,
+ AK_Construct,
+ AK_Destroy,
+};
+
+// The order of this enum is important for diagnostics.
+enum CheckSubobjectKind {
+ CSK_Base,
+ CSK_Derived,
+ CSK_Field,
+ CSK_ArrayToPointer,
+ CSK_ArrayIndex,
+ CSK_Real,
+ CSK_Imag
+};
+
+namespace interp {
+class Frame;
+class SourceInfo;
+
+/// Interface for the VM to interact with the AST walker's context.
+class State {
+public:
+ virtual ~State();
+
+ virtual bool checkingForUndefinedBehavior() const = 0;
+ virtual bool checkingPotentialConstantExpression() const = 0;
+ virtual bool noteUndefinedBehavior() = 0;
+ virtual bool keepEvaluatingAfterFailure() const = 0;
+ virtual Frame *getCurrentFrame() = 0;
+ virtual const Frame *getBottomFrame() const = 0;
+ virtual bool hasActiveDiagnostic() = 0;
+ virtual void setActiveDiagnostic(bool Flag) = 0;
+ virtual void setFoldFailureDiagnostic(bool Flag) = 0;
+ virtual Expr::EvalStatus &getEvalStatus() const = 0;
+ virtual ASTContext &getCtx() const = 0;
+ virtual bool hasPriorDiagnostic() = 0;
+ virtual unsigned getCallStackDepth() = 0;
+
+public:
+ // Diagnose that the evaluation could not be folded (FF => FoldFailure)
+ OptionalDiagnostic
+ FFDiag(SourceLocation Loc,
+ diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0);
+
+ OptionalDiagnostic
+ FFDiag(const Expr *E,
+ diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0);
+
+ OptionalDiagnostic
+ FFDiag(const SourceInfo &SI,
+ diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0);
+
+ /// Diagnose that the evaluation does not produce a C++11 core constant
+ /// expression.
+ ///
+ /// FIXME: Stop evaluating if we're in EM_ConstantExpression or
+ /// EM_PotentialConstantExpression mode and we produce one of these.
+ OptionalDiagnostic
+ CCEDiag(SourceLocation Loc,
+ diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0);
+
+ OptionalDiagnostic
+ CCEDiag(const Expr *E,
+ diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0);
+
+ OptionalDiagnostic
+ CCEDiag(const SourceInfo &SI,
+ diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr,
+ unsigned ExtraNotes = 0);
+
+ /// Add a note to a prior diagnostic.
+ OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId);
+
+ /// Add a stack of notes to a prior diagnostic.
+ void addNotes(ArrayRef<PartialDiagnosticAt> Diags);
+
+ /// Directly reports a diagnostic message.
+ DiagnosticBuilder report(SourceLocation Loc, diag::kind DiagId);
+
+ const LangOptions &getLangOpts() const;
+
+private:
+ void addCallStack(unsigned Limit);
+
+ PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId);
+
+ OptionalDiagnostic diag(SourceLocation Loc, diag::kind DiagId,
+ unsigned ExtraNotes, bool IsCCEDiag);
+};
+
+} // namespace interp
+} // namespace clang
+
+#endif
diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp
index 727a905d08a1..069add8464ae 100644
--- a/lib/AST/ItaniumCXXABI.cpp
+++ b/lib/AST/ItaniumCXXABI.cpp
@@ -19,10 +19,12 @@
#include "CXXABI.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Mangle.h"
#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/iterator.h"
using namespace clang;
@@ -73,10 +75,33 @@ struct DecompositionDeclName {
}
namespace llvm {
+template<typename T> bool isDenseMapKeyEmpty(T V) {
+ return llvm::DenseMapInfo<T>::isEqual(
+ V, llvm::DenseMapInfo<T>::getEmptyKey());
+}
+template<typename T> bool isDenseMapKeyTombstone(T V) {
+ return llvm::DenseMapInfo<T>::isEqual(
+ V, llvm::DenseMapInfo<T>::getTombstoneKey());
+}
+
+template<typename T>
+Optional<bool> areDenseMapKeysEqualSpecialValues(T LHS, T RHS) {
+ bool LHSEmpty = isDenseMapKeyEmpty(LHS);
+ bool RHSEmpty = isDenseMapKeyEmpty(RHS);
+ if (LHSEmpty || RHSEmpty)
+ return LHSEmpty && RHSEmpty;
+
+ bool LHSTombstone = isDenseMapKeyTombstone(LHS);
+ bool RHSTombstone = isDenseMapKeyTombstone(RHS);
+ if (LHSTombstone || RHSTombstone)
+ return LHSTombstone && RHSTombstone;
+
+ return None;
+}
+
template<>
struct DenseMapInfo<DecompositionDeclName> {
using ArrayInfo = llvm::DenseMapInfo<ArrayRef<const BindingDecl*>>;
- using IdentInfo = llvm::DenseMapInfo<const IdentifierInfo*>;
static DecompositionDeclName getEmptyKey() {
return {ArrayInfo::getEmptyKey()};
}
@@ -88,10 +113,10 @@ struct DenseMapInfo<DecompositionDeclName> {
return llvm::hash_combine_range(Key.begin(), Key.end());
}
static bool isEqual(DecompositionDeclName LHS, DecompositionDeclName RHS) {
- if (ArrayInfo::isEqual(LHS.Bindings, ArrayInfo::getEmptyKey()))
- return ArrayInfo::isEqual(RHS.Bindings, ArrayInfo::getEmptyKey());
- if (ArrayInfo::isEqual(LHS.Bindings, ArrayInfo::getTombstoneKey()))
- return ArrayInfo::isEqual(RHS.Bindings, ArrayInfo::getTombstoneKey());
+ if (Optional<bool> Result = areDenseMapKeysEqualSpecialValues(
+ LHS.Bindings, RHS.Bindings))
+ return *Result;
+
return LHS.Bindings.size() == RHS.Bindings.size() &&
std::equal(LHS.begin(), LHS.end(), RHS.begin());
}
@@ -103,29 +128,32 @@ namespace {
/// Keeps track of the mangled names of lambda expressions and block
/// literals within a particular context.
class ItaniumNumberingContext : public MangleNumberingContext {
- llvm::DenseMap<const Type *, unsigned> ManglingNumbers;
+ ItaniumMangleContext *Mangler;
+ llvm::StringMap<unsigned> LambdaManglingNumbers;
+ unsigned BlockManglingNumber = 0;
llvm::DenseMap<const IdentifierInfo *, unsigned> VarManglingNumbers;
llvm::DenseMap<const IdentifierInfo *, unsigned> TagManglingNumbers;
llvm::DenseMap<DecompositionDeclName, unsigned>
DecompsitionDeclManglingNumbers;
public:
+ ItaniumNumberingContext(ItaniumMangleContext *Mangler) : Mangler(Mangler) {}
+
unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {
- const FunctionProtoType *Proto =
- CallOperator->getType()->getAs<FunctionProtoType>();
- ASTContext &Context = CallOperator->getASTContext();
+ const CXXRecordDecl *Lambda = CallOperator->getParent();
+ assert(Lambda->isLambda());
+
+ // Computation of the <lambda-sig> is non-trivial and subtle. Rather than
+ // duplicating it here, just mangle the <lambda-sig> directly.
+ llvm::SmallString<128> LambdaSig;
+ llvm::raw_svector_ostream Out(LambdaSig);
+ Mangler->mangleLambdaSig(Lambda, Out);
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.Variadic = Proto->isVariadic();
- QualType Key =
- Context.getFunctionType(Context.VoidTy, Proto->getParamTypes(), EPI);
- Key = Context.getCanonicalType(Key);
- return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
+ return ++LambdaManglingNumbers[LambdaSig];
}
unsigned getManglingNumber(const BlockDecl *BD) override {
- const Type *Ty = nullptr;
- return ++ManglingNumbers[Ty];
+ return ++BlockManglingNumber;
}
unsigned getStaticLocalNumber(const VarDecl *VD) override {
@@ -154,10 +182,13 @@ public:
};
class ItaniumCXXABI : public CXXABI {
+private:
+ std::unique_ptr<MangleContext> Mangler;
protected:
ASTContext &Context;
public:
- ItaniumCXXABI(ASTContext &Ctx) : Context(Ctx) { }
+ ItaniumCXXABI(ASTContext &Ctx)
+ : Mangler(Ctx.createMangleContext()), Context(Ctx) {}
MemberPointerInfo
getMemberPointerInfo(const MemberPointerType *MPT) const override {
@@ -177,7 +208,7 @@ public:
if (!isVariadic && T.isWindowsGNUEnvironment() &&
T.getArch() == llvm::Triple::x86)
return CC_X86ThisCall;
- return CC_C;
+ return Context.getTargetInfo().getDefaultCallingConv();
}
// We cheat and just check that the class has a vtable pointer, and that it's
@@ -218,7 +249,8 @@ public:
std::unique_ptr<MangleNumberingContext>
createMangleNumberingContext() const override {
- return llvm::make_unique<ItaniumNumberingContext>();
+ return std::make_unique<ItaniumNumberingContext>(
+ cast<ItaniumMangleContext>(Mangler.get()));
}
};
}
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 6c813f09a4b3..c55a90137578 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -170,6 +170,8 @@ public:
void mangleStringLiteral(const StringLiteral *, raw_ostream &) override;
+ void mangleLambdaSig(const CXXRecordDecl *Lambda, raw_ostream &) override;
+
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
// Lambda closure types are already numbered.
if (isLambda(ND))
@@ -424,6 +426,7 @@ public:
void mangleName(const NamedDecl *ND);
void mangleType(QualType T);
void mangleNameOrStandardSubstitution(const NamedDecl *ND);
+ void mangleLambdaSig(const CXXRecordDecl *Lambda);
private:
@@ -513,7 +516,7 @@ private:
#define ABSTRACT_TYPE(CLASS, PARENT)
#define NON_CANONICAL_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T);
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
void mangleType(const TagType*);
void mangleType(TemplateName);
@@ -550,7 +553,7 @@ private:
void mangleTemplateArgs(const TemplateArgumentList &AL);
void mangleTemplateArg(TemplateArgument A);
- void mangleTemplateParameter(unsigned Index);
+ void mangleTemplateParameter(unsigned Depth, unsigned Index);
void mangleFunctionParam(const ParmVarDecl *parm);
@@ -965,8 +968,8 @@ void CXXNameMangler::mangleUnscopedTemplateName(
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
assert(!AdditionalAbiTags &&
"template template param cannot have abi tags");
- mangleTemplateParameter(TTP->getIndex());
- } else if (isa<BuiltinTemplateDecl>(ND)) {
+ mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
+ } else if (isa<BuiltinTemplateDecl>(ND) || isa<ConceptDecl>(ND)) {
mangleUnscopedName(ND, AdditionalAbiTags);
} else {
mangleUnscopedName(ND->getTemplatedDecl(), AdditionalAbiTags);
@@ -1321,7 +1324,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
// We must have an anonymous union or struct declaration.
- const RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl();
+ const RecordDecl *RD = VD->getType()->castAs<RecordType>()->getDecl();
// Itanium C++ ABI 5.1.2:
//
@@ -1685,17 +1688,45 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) {
// ::= Ty # template type parameter
// ::= Tn <type> # template non-type parameter
// ::= Tt <template-param-decl>* E # template template parameter
+// ::= Tp <template-param-decl> # template parameter pack
void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) {
- if (isa<TemplateTypeParmDecl>(Decl)) {
+ if (auto *Ty = dyn_cast<TemplateTypeParmDecl>(Decl)) {
+ if (Ty->isParameterPack())
+ Out << "Tp";
Out << "Ty";
} else if (auto *Tn = dyn_cast<NonTypeTemplateParmDecl>(Decl)) {
- Out << "Tn";
- mangleType(Tn->getType());
+ if (Tn->isExpandedParameterPack()) {
+ for (unsigned I = 0, N = Tn->getNumExpansionTypes(); I != N; ++I) {
+ Out << "Tn";
+ mangleType(Tn->getExpansionType(I));
+ }
+ } else {
+ QualType T = Tn->getType();
+ if (Tn->isParameterPack()) {
+ Out << "Tp";
+ if (auto *PackExpansion = T->getAs<PackExpansionType>())
+ T = PackExpansion->getPattern();
+ }
+ Out << "Tn";
+ mangleType(T);
+ }
} else if (auto *Tt = dyn_cast<TemplateTemplateParmDecl>(Decl)) {
- Out << "Tt";
- for (auto *Param : *Tt->getTemplateParameters())
- mangleTemplateParamDecl(Param);
- Out << "E";
+ if (Tt->isExpandedParameterPack()) {
+ for (unsigned I = 0, N = Tt->getNumExpansionTemplateParameters(); I != N;
+ ++I) {
+ Out << "Tt";
+ for (auto *Param : *Tt->getExpansionTemplateParameters(I))
+ mangleTemplateParamDecl(Param);
+ Out << "E";
+ }
+ } else {
+ if (Tt->isParameterPack())
+ Out << "Tp";
+ Out << "Tt";
+ for (auto *Param : *Tt->getTemplateParameters())
+ mangleTemplateParamDecl(Param);
+ Out << "E";
+ }
}
}
@@ -1726,12 +1757,7 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
}
Out << "Ul";
- for (auto *D : Lambda->getLambdaExplicitTemplateParameters())
- mangleTemplateParamDecl(D);
- const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
- getAs<FunctionProtoType>();
- mangleBareFunctionType(Proto, /*MangleReturnType=*/false,
- Lambda->getLambdaStaticInvoker());
+ mangleLambdaSig(Lambda);
Out << "E";
// The number is omitted for the first closure type with a given
@@ -1746,6 +1772,15 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
Out << '_';
}
+void CXXNameMangler::mangleLambdaSig(const CXXRecordDecl *Lambda) {
+ for (auto *D : Lambda->getLambdaExplicitTemplateParameters())
+ mangleTemplateParamDecl(D);
+ const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
+ getAs<FunctionProtoType>();
+ mangleBareFunctionType(Proto, /*MangleReturnType=*/false,
+ Lambda->getLambdaStaticInvoker());
+}
+
void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
switch (qualifier->getKind()) {
case NestedNameSpecifier::Global:
@@ -1852,10 +1887,10 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND,
// <template-template-param> ::= <template-param>
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
- mangleTemplateParameter(TTP->getIndex());
+ mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
} else {
manglePrefix(getEffectiveDeclContext(ND), NoFunction);
- if (isa<BuiltinTemplateDecl>(ND))
+ if (isa<BuiltinTemplateDecl>(ND) || isa<ConceptDecl>(ND))
mangleUnqualifiedName(ND, nullptr);
else
mangleUnqualifiedName(ND->getTemplatedDecl(), nullptr);
@@ -1885,8 +1920,8 @@ void CXXNameMangler::mangleType(TemplateName TN) {
goto HaveDecl;
HaveDecl:
- if (isa<TemplateTemplateParmDecl>(TD))
- mangleTemplateParameter(cast<TemplateTemplateParmDecl>(TD)->getIndex());
+ if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TD))
+ mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
else
mangleName(TD);
break;
@@ -2464,7 +2499,7 @@ void CXXNameMangler::mangleType(QualType T) {
case Type::CLASS: \
mangleType(static_cast<const CLASS##Type*>(ty)); \
break;
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
}
@@ -2671,6 +2706,15 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
Out << type_name.size() << type_name; \
break;
#include "clang/Basic/OpenCLExtensionTypes.def"
+ // The SVE types are effectively target-specific. The mangling scheme
+ // is defined in the appendices to the Procedure Call Standard for the
+ // Arm Architecture.
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id: \
+ type_name = Name; \
+ Out << 'u' << type_name.size() << type_name; \
+ break;
+#include "clang/Basic/AArch64SVEACLETypes.def"
}
}
@@ -2955,7 +2999,7 @@ void CXXNameMangler::mangleType(const MemberPointerType *T) {
// <type> ::= <template-param>
void CXXNameMangler::mangleType(const TemplateTypeParmType *T) {
- mangleTemplateParameter(T->getIndex());
+ mangleTemplateParameter(T->getDepth(), T->getIndex());
}
// <type> ::= <template-param>
@@ -3526,7 +3570,7 @@ void CXXNameMangler::mangleDeclRefExpr(const NamedDecl *D) {
case Decl::NonTypeTemplateParm:
const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D);
- mangleTemplateParameter(PD->getIndex());
+ mangleTemplateParameter(PD->getDepth(), PD->getIndex());
break;
}
}
@@ -4046,6 +4090,17 @@ recurse:
break;
}
+ case Expr::CXXRewrittenBinaryOperatorClass: {
+ // The mangled form represents the original syntax.
+ CXXRewrittenBinaryOperator::DecomposedForm Decomposed =
+ cast<CXXRewrittenBinaryOperator>(E)->getDecomposedForm();
+ mangleOperatorName(BinaryOperator::getOverloadedOperator(Decomposed.Opcode),
+ /*Arity=*/2);
+ mangleExpression(Decomposed.LHS);
+ mangleExpression(Decomposed.RHS);
+ break;
+ }
+
case Expr::ConditionalOperatorClass: {
const ConditionalOperator *CO = cast<ConditionalOperator>(E);
mangleOperatorName(OO_Conditional, /*Arity=*/3);
@@ -4123,6 +4178,18 @@ recurse:
mangleExpression(cast<ParenExpr>(E)->getSubExpr(), Arity);
break;
+
+ case Expr::ConceptSpecializationExprClass: {
+ // <expr-primary> ::= L <mangled-name> E # external name
+ Out << "L_Z";
+ auto *CSE = cast<ConceptSpecializationExpr>(E);
+ mangleTemplateName(CSE->getNamedConcept(),
+ CSE->getTemplateArguments().data(),
+ CSE->getTemplateArguments().size());
+ Out << 'E';
+ break;
+ }
+
case Expr::DeclRefExprClass:
mangleDeclRefExpr(cast<DeclRefExpr>(E)->getDecl());
break;
@@ -4229,8 +4296,11 @@ recurse:
}
case Expr::GNUNullExprClass:
- // FIXME: should this really be mangled the same as nullptr?
- // fallthrough
+ // Mangle as if an integer literal 0.
+ Out << 'L';
+ mangleType(E->getType());
+ Out << "0E";
+ break;
case Expr::CXXNullPtrLiteralExprClass: {
Out << "LDnE";
@@ -4255,13 +4325,13 @@ recurse:
Out << "sZ";
const NamedDecl *Pack = SPE->getPack();
if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack))
- mangleTemplateParameter(TTP->getIndex());
+ mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
else if (const NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Pack))
- mangleTemplateParameter(NTTP->getIndex());
+ mangleTemplateParameter(NTTP->getDepth(), NTTP->getIndex());
else if (const TemplateTemplateParmDecl *TempTP
= dyn_cast<TemplateTemplateParmDecl>(Pack))
- mangleTemplateParameter(TempTP->getIndex());
+ mangleTemplateParameter(TempTP->getDepth(), TempTP->getIndex());
else
mangleFunctionParam(cast<ParmVarDecl>(Pack));
break;
@@ -4548,13 +4618,21 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
}
}
-void CXXNameMangler::mangleTemplateParameter(unsigned Index) {
+void CXXNameMangler::mangleTemplateParameter(unsigned Depth, unsigned Index) {
// <template-param> ::= T_ # first template parameter
// ::= T <parameter-2 non-negative number> _
- if (Index == 0)
- Out << "T_";
- else
- Out << 'T' << (Index - 1) << '_';
+ // ::= TL <L-1 non-negative number> __
+ // ::= TL <L-1 non-negative number> _
+ // <parameter-2 non-negative number> _
+ //
+ // The latter two manglings are from a proposal here:
+ // https://github.com/itanium-cxx-abi/cxx-abi/issues/31#issuecomment-528122117
+ Out << 'T';
+ if (Depth != 0)
+ Out << 'L' << (Depth - 1) << '_';
+ if (Index != 0)
+ Out << (Index - 1);
+ Out << '_';
}
void CXXNameMangler::mangleSeqID(unsigned SeqID) {
@@ -5071,6 +5149,12 @@ void ItaniumMangleContextImpl::mangleStringLiteral(const StringLiteral *, raw_os
llvm_unreachable("Can't mangle string literals");
}
+void ItaniumMangleContextImpl::mangleLambdaSig(const CXXRecordDecl *Lambda,
+ raw_ostream &Out) {
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.mangleLambdaSig(Lambda);
+}
+
ItaniumMangleContext *
ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
return new ItaniumMangleContextImpl(Context, Diags);
diff --git a/lib/AST/JSONNodeDumper.cpp b/lib/AST/JSONNodeDumper.cpp
index 04b933b0fb30..f60d761c996c 100644
--- a/lib/AST/JSONNodeDumper.cpp
+++ b/lib/AST/JSONNodeDumper.cpp
@@ -66,6 +66,10 @@ void JSONNodeDumper::Visit(const Stmt *S) {
void JSONNodeDumper::Visit(const Type *T) {
JOS.attribute("id", createPointerRepresentation(T));
+
+ if (!T)
+ return;
+
JOS.attribute("kind", (llvm::Twine(T->getTypeClassName()) + "Type").str());
JOS.attribute("type", createQualType(QualType(T, 0), /*Desugar*/ false));
attributeOnlyIfTrue("isDependent", T->isDependentType());
@@ -107,9 +111,14 @@ void JSONNodeDumper::Visit(const Decl *D) {
if (const auto *ND = dyn_cast<NamedDecl>(D))
attributeOnlyIfTrue("isHidden", ND->isHidden());
- if (D->getLexicalDeclContext() != D->getDeclContext())
- JOS.attribute("parentDeclContext",
- createPointerRepresentation(D->getDeclContext()));
+ if (D->getLexicalDeclContext() != D->getDeclContext()) {
+ // Because of multiple inheritance, a DeclContext pointer does not produce
+ // the same pointer representation as a Decl pointer that references the
+ // same AST Node.
+ const auto *ParentDeclContextDecl = dyn_cast<Decl>(D->getDeclContext());
+ JOS.attribute("parentDeclContextId",
+ createPointerRepresentation(ParentDeclContextDecl));
+ }
addPreviousDeclaration(D);
InnerDeclVisitor::Visit(D);
@@ -171,12 +180,30 @@ void JSONNodeDumper::Visit(const GenericSelectionExpr::ConstAssociation &A) {
attributeOnlyIfTrue("selected", A.isSelected());
}
+void JSONNodeDumper::writeIncludeStack(PresumedLoc Loc, bool JustFirst) {
+ if (Loc.isInvalid())
+ return;
+
+ JOS.attributeBegin("includedFrom");
+ JOS.objectBegin();
+
+ if (!JustFirst) {
+ // Walk the stack recursively, then print out the presumed location.
+ writeIncludeStack(SM.getPresumedLoc(Loc.getIncludeLoc()));
+ }
+
+ JOS.attribute("file", Loc.getFilename());
+ JOS.objectEnd();
+ JOS.attributeEnd();
+}
+
void JSONNodeDumper::writeBareSourceLocation(SourceLocation Loc,
bool IsSpelling) {
PresumedLoc Presumed = SM.getPresumedLoc(Loc);
unsigned ActualLine = IsSpelling ? SM.getSpellingLineNumber(Loc)
: SM.getExpansionLineNumber(Loc);
if (Presumed.isValid()) {
+ JOS.attribute("offset", SM.getDecomposedLoc(Loc).second);
if (LastLocFilename != Presumed.getFilename()) {
JOS.attribute("file", Presumed.getFilename());
JOS.attribute("line", ActualLine);
@@ -193,6 +220,12 @@ void JSONNodeDumper::writeBareSourceLocation(SourceLocation Loc,
LastLocFilename = Presumed.getFilename();
LastLocPresumedLine = PresumedLine;
LastLocLine = ActualLine;
+
+ // Orthogonal to the file, line, and column de-duplication is whether the
+ // given location was a result of an include. If so, print where the
+ // include location came from.
+ writeIncludeStack(SM.getPresumedLoc(Presumed.getIncludeLoc()),
+ /*JustFirst*/ true);
}
}
@@ -238,6 +271,8 @@ llvm::json::Object JSONNodeDumper::createQualType(QualType QT, bool Desugar) {
SplitQualType DSQT = QT.getSplitDesugaredType();
if (DSQT != SQT)
Ret["desugaredQualType"] = QualType::getAsString(DSQT, PrintPolicy);
+ if (const auto *TT = QT->getAs<TypedefType>())
+ Ret["typeAliasDeclId"] = createPointerRepresentation(TT->getDecl());
}
return Ret;
}
@@ -275,7 +310,7 @@ llvm::json::Array JSONNodeDumper::createCastPath(const CastExpr *C) {
for (auto I = C->path_begin(), E = C->path_end(); I != E; ++I) {
const CXXBaseSpecifier *Base = *I;
const auto *RD =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(Base->getType()->castAs<RecordType>()->getDecl());
llvm::json::Object Val{{"name", RD->getName()}};
if (Base->isVirtual())
@@ -839,6 +874,12 @@ void JSONNodeDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *LSD) {
switch (LSD->getLanguage()) {
case LinkageSpecDecl::lang_c: Lang = "C"; break;
case LinkageSpecDecl::lang_cxx: Lang = "C++"; break;
+ case LinkageSpecDecl::lang_cxx_11:
+ Lang = "C++11";
+ break;
+ case LinkageSpecDecl::lang_cxx_14:
+ Lang = "C++14";
+ break;
}
JOS.attribute("language", Lang);
attributeOnlyIfTrue("hasBraces", LSD->hasBraces());
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index 625282368a4d..32d466cb5718 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -122,15 +122,21 @@ void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) {
if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
// If we have an asm name, then we use it as the mangling.
+ // If the label isn't literal, or if this is an alias for an LLVM intrinsic,
+ // do not add a "\01" prefix.
+ if (!ALA->getIsLiteralLabel() || ALA->getLabel().startswith("llvm.")) {
+ Out << ALA->getLabel();
+ return;
+ }
+
// Adding the prefix can cause problems when one file has a "foo" and
// another has a "\01foo". That is known to happen on ELF with the
// tricks normally used for producing aliases (PR9177). Fortunately the
// llvm mangler on ELF is a nop, so we can just avoid adding the \01
- // marker. We also avoid adding the marker if this is an alias for an
- // LLVM intrinsic.
+ // marker.
char GlobalPrefix =
getASTContext().getTargetInfo().getDataLayout().getGlobalPrefix();
- if (GlobalPrefix && !ALA->getLabel().startswith("llvm."))
+ if (GlobalPrefix)
Out << '\01'; // LLVM IR Marker for __asm("foo")
Out << ALA->getLabel();
@@ -380,7 +386,7 @@ public:
auto hasDefaultCXXMethodCC = [](ASTContext &C, const CXXMethodDecl *MD) {
auto DefaultCC = C.getDefaultCallingConvention(/*IsVariadic=*/false,
/*IsCXXMethod=*/true);
- auto CC = MD->getType()->getAs<FunctionProtoType>()->getCallConv();
+ auto CC = MD->getType()->castAs<FunctionProtoType>()->getCallConv();
return CC == DefaultCC;
};
@@ -470,7 +476,7 @@ private:
};
ASTNameGenerator::ASTNameGenerator(ASTContext &Ctx)
- : Impl(llvm::make_unique<Implementation>(Ctx)) {}
+ : Impl(std::make_unique<Implementation>(Ctx)) {}
ASTNameGenerator::~ASTNameGenerator() {}
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index 4dc4156df9ca..074abba3d458 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -82,7 +82,7 @@ public:
if (!isVariadic &&
Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
return CC_X86ThisCall;
- return CC_C;
+ return Context.getTargetInfo().getDefaultCallingConv();
}
bool isNearlyEmpty(const CXXRecordDecl *RD) const override {
@@ -132,7 +132,7 @@ public:
std::unique_ptr<MangleNumberingContext>
createMangleNumberingContext() const override {
- return llvm::make_unique<MicrosoftNumberingContext>();
+ return std::make_unique<MicrosoftNumberingContext>();
}
};
}
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 5e9358e24fc9..f871a1b99900 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -27,11 +27,11 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/JamCRC.h"
-#include "llvm/Support/xxhash.h"
+#include "llvm/Support/CRC.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/xxhash.h"
using namespace clang;
@@ -364,7 +364,7 @@ private:
#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T, \
Qualifiers Quals, \
SourceRange Range);
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
#undef ABSTRACT_TYPE
#undef NON_CANONICAL_TYPE
#undef TYPE
@@ -615,6 +615,8 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
case MSInheritanceAttr::Keyword_multiple_inheritance: Code = '0'; break;
case MSInheritanceAttr::Keyword_virtual_inheritance: Code = 'F'; break;
case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'G'; break;
+ case MSInheritanceAttr::SpellingNotCalculated:
+ llvm_unreachable("not reachable");
}
Out << '$' << Code;
@@ -646,6 +648,8 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
case MSInheritanceAttr::Keyword_multiple_inheritance: Code = 'H'; break;
case MSInheritanceAttr::Keyword_virtual_inheritance: Code = 'I'; break;
case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'J'; break;
+ case MSInheritanceAttr::SpellingNotCalculated:
+ llvm_unreachable("not reachable");
}
// If non-virtual, mangle the name. If virtual, mangle as a virtual memptr
@@ -842,7 +846,7 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
TemplateArgStringStorage.save(TemplateMangling.str());
}
} else {
- Out << Found->second; // Outputs a StringRef.
+ Out << Found->second << '@'; // Outputs a StringRef.
}
} else {
Out << Found->second; // Outputs a back reference (an int).
@@ -868,16 +872,11 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
}
if (const DecompositionDecl *DD = dyn_cast<DecompositionDecl>(ND)) {
- // FIXME: Invented mangling for decomposition declarations:
- // [X,Y,Z]
- // where X,Y,Z are the names of the bindings.
- llvm::SmallString<128> Name("[");
- for (auto *BD : DD->bindings()) {
- if (Name.size() > 1)
- Name += ',';
- Name += BD->getDeclName().getAsIdentifierInfo()->getName();
- }
- Name += ']';
+ // Decomposition declarations are considered anonymous, and get
+ // numbered with a $S prefix.
+ llvm::SmallString<64> Name("$S");
+ // Get a unique id for the anonymous struct.
+ Name += llvm::utostr(Context.getAnonymousStructId(DD) + 1);
mangleSourceName(Name);
break;
}
@@ -1942,7 +1941,7 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
case Type::CLASS: \
mangleType(cast<CLASS##Type>(ty), Quals, Range); \
break;
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
#undef ABSTRACT_TYPE
#undef NON_CANONICAL_TYPE
#undef TYPE
@@ -2109,6 +2108,9 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
mangleArtificialTagType(TTK_Struct, "_Half", {"__clang"});
break;
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
case BuiltinType::ShortAccum:
case BuiltinType::Accum:
case BuiltinType::LongAccum:
diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp
index 5104dc59d621..ae6ff04f5126 100644
--- a/lib/AST/NSAPI.cpp
+++ b/lib/AST/NSAPI.cpp
@@ -75,17 +75,6 @@ Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {
return NSStringSelectors[MK];
}
-Optional<NSAPI::NSStringMethodKind>
-NSAPI::getNSStringMethodKind(Selector Sel) const {
- for (unsigned i = 0; i != NumNSStringMethods; ++i) {
- NSStringMethodKind MK = NSStringMethodKind(i);
- if (Sel == getNSStringSelector(MK))
- return MK;
- }
-
- return None;
-}
-
Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
if (NSArraySelectors[MK].isNull()) {
Selector Sel;
@@ -482,6 +471,9 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
case BuiltinType::OCLReserveID:
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
case BuiltinType::BoundMember:
case BuiltinType::Dependent:
case BuiltinType::Overload:
diff --git a/lib/AST/OpenMPClause.cpp b/lib/AST/OpenMPClause.cpp
index 9d8a7ebc3023..fe1334469d48 100644
--- a/lib/AST/OpenMPClause.cpp
+++ b/lib/AST/OpenMPClause.cpp
@@ -43,6 +43,8 @@ OMPClause::child_range OMPClause::used_children() {
#include "clang/Basic/OpenMPKinds.def"
case OMPC_threadprivate:
case OMPC_uniform:
+ case OMPC_device_type:
+ case OMPC_match:
case OMPC_unknown:
break;
}
@@ -82,9 +84,16 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
return static_cast<const OMPThreadLimitClause *>(C);
case OMPC_device:
return static_cast<const OMPDeviceClause *>(C);
+ case OMPC_grainsize:
+ return static_cast<const OMPGrainsizeClause *>(C);
+ case OMPC_num_tasks:
+ return static_cast<const OMPNumTasksClause *>(C);
+ case OMPC_final:
+ return static_cast<const OMPFinalClause *>(C);
+ case OMPC_priority:
+ return static_cast<const OMPPriorityClause *>(C);
case OMPC_default:
case OMPC_proc_bind:
- case OMPC_final:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_allocator:
@@ -110,10 +119,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
case OMPC_threads:
case OMPC_simd:
case OMPC_map:
- case OMPC_priority:
- case OMPC_grainsize:
case OMPC_nogroup:
- case OMPC_num_tasks:
case OMPC_hint:
case OMPC_defaultmap:
case OMPC_unknown:
@@ -127,6 +133,8 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
break;
}
@@ -203,6 +211,8 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C)
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
break;
}
@@ -228,6 +238,30 @@ OMPClause::child_range OMPIfClause::used_children() {
return child_range(&Condition, &Condition + 1);
}
+OMPClause::child_range OMPGrainsizeClause::used_children() {
+ if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
+ return child_range(C, C + 1);
+ return child_range(&Grainsize, &Grainsize + 1);
+}
+
+OMPClause::child_range OMPNumTasksClause::used_children() {
+ if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
+ return child_range(C, C + 1);
+ return child_range(&NumTasks, &NumTasks + 1);
+}
+
+OMPClause::child_range OMPFinalClause::used_children() {
+ if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
+ return child_range(C, C + 1);
+ return child_range(&Condition, &Condition + 1);
+}
+
+OMPClause::child_range OMPPriorityClause::used_children() {
+ if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
+ return child_range(C, C + 1);
+ return child_range(&Priority, &Priority + 1);
+}
+
OMPOrderedClause *OMPOrderedClause::Create(const ASTContext &C, Expr *Num,
unsigned NumLoops,
SourceLocation StartLoc,
@@ -429,15 +463,23 @@ void OMPLinearClause::setFinals(ArrayRef<Expr *> FL) {
std::copy(FL.begin(), FL.end(), getUpdates().end());
}
+void OMPLinearClause::setUsedExprs(ArrayRef<Expr *> UE) {
+ assert(
+ UE.size() == varlist_size() + 1 &&
+ "Number of used expressions is not the same as the preallocated buffer");
+ std::copy(UE.begin(), UE.end(), getFinals().end() + 2);
+}
+
OMPLinearClause *OMPLinearClause::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
OpenMPLinearClauseKind Modifier, SourceLocation ModifierLoc,
SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL,
ArrayRef<Expr *> PL, ArrayRef<Expr *> IL, Expr *Step, Expr *CalcStep,
Stmt *PreInit, Expr *PostUpdate) {
- // Allocate space for 4 lists (Vars, Inits, Updates, Finals) and 2 expressions
- // (Step and CalcStep).
- void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size() + 2));
+ // Allocate space for 5 lists (Vars, Inits, Updates, Finals), 2 expressions
+ // (Step and CalcStep), list of used expression + step.
+ void *Mem =
+ C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size() + 2 + VL.size() + 1));
OMPLinearClause *Clause = new (Mem) OMPLinearClause(
StartLoc, LParenLoc, Modifier, ModifierLoc, ColonLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
@@ -449,6 +491,8 @@ OMPLinearClause *OMPLinearClause::Create(
nullptr);
std::fill(Clause->getUpdates().end(), Clause->getUpdates().end() + VL.size(),
nullptr);
+ std::fill(Clause->getUsedExprs().begin(), Clause->getUsedExprs().end(),
+ nullptr);
Clause->setStep(Step);
Clause->setCalcStep(CalcStep);
Clause->setPreInitStmt(PreInit);
@@ -458,12 +502,19 @@ OMPLinearClause *OMPLinearClause::Create(
OMPLinearClause *OMPLinearClause::CreateEmpty(const ASTContext &C,
unsigned NumVars) {
- // Allocate space for 4 lists (Vars, Inits, Updates, Finals) and 2 expressions
- // (Step and CalcStep).
- void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * NumVars + 2));
+ // Allocate space for 5 lists (Vars, Inits, Updates, Finals), 2 expressions
+ // (Step and CalcStep), list of used expression + step.
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * NumVars + 2 + NumVars +1));
return new (Mem) OMPLinearClause(NumVars);
}
+OMPClause::child_range OMPLinearClause::used_children() {
+ // Range includes only non-nullptr elements.
+ return child_range(
+ reinterpret_cast<Stmt **>(getUsedExprs().begin()),
+ reinterpret_cast<Stmt **>(llvm::find(getUsedExprs(), nullptr)));
+}
+
OMPAlignedClause *
OMPAlignedClause::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation ColonLoc,
diff --git a/lib/AST/PrintfFormatString.cpp b/lib/AST/PrintfFormatString.cpp
index a1207aae5aa2..bae60d464407 100644
--- a/lib/AST/PrintfFormatString.cpp
+++ b/lib/AST/PrintfFormatString.cpp
@@ -463,6 +463,23 @@ bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,
return false;
}
+bool clang::analyze_format_string::parseFormatStringHasFormattingSpecifiers(
+ const char *Begin, const char *End, const LangOptions &LO,
+ const TargetInfo &Target) {
+ unsigned ArgIndex = 0;
+ // Keep looking for a formatting specifier until we have exhausted the string.
+ FormatStringHandler H;
+ while (Begin != End) {
+ const PrintfSpecifierResult &FSR =
+ ParsePrintfSpecifier(H, Begin, End, ArgIndex, LO, Target, false, false);
+ if (FSR.shouldStop())
+ break;
+ if (FSR.hasValue())
+ return true;
+ }
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Methods on PrintfSpecifier.
//===----------------------------------------------------------------------===//
@@ -769,6 +786,9 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
case BuiltinType::Id:
#include "clang/Basic/OpenCLExtensionTypes.def"
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
#define SIGNED_TYPE(Id, SingletonId)
#define UNSIGNED_TYPE(Id, SingletonId)
#define FLOATING_TYPE(Id, SingletonId)
diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp
index df53b7fa1004..83e8a0b942a4 100644
--- a/lib/AST/RawCommentList.cpp
+++ b/lib/AST/RawCommentList.cpp
@@ -275,27 +275,25 @@ void RawCommentList::addComment(const RawComment &RC,
if (RC.isInvalid())
return;
- // Check if the comments are not in source order.
- while (!Comments.empty() &&
- !SourceMgr.isBeforeInTranslationUnit(Comments.back()->getBeginLoc(),
- RC.getBeginLoc())) {
- // If they are, just pop a few last comments that don't fit.
- // This happens if an \#include directive contains comments.
- Comments.pop_back();
- }
-
// Ordinary comments are not interesting for us.
if (RC.isOrdinary() && !CommentOpts.ParseAllComments)
return;
+ std::pair<FileID, unsigned> Loc =
+ SourceMgr.getDecomposedLoc(RC.getBeginLoc());
+
+ const FileID CommentFile = Loc.first;
+ const unsigned CommentOffset = Loc.second;
+
// If this is the first Doxygen comment, save it (because there isn't
// anything to merge it with).
- if (Comments.empty()) {
- Comments.push_back(new (Allocator) RawComment(RC));
+ if (OrderedComments[CommentFile].empty()) {
+ OrderedComments[CommentFile][CommentOffset] =
+ new (Allocator) RawComment(RC);
return;
}
- const RawComment &C1 = *Comments.back();
+ const RawComment &C1 = *OrderedComments[CommentFile].rbegin()->second;
const RawComment &C2 = RC;
// Merge comments only if there is only whitespace between them.
@@ -318,21 +316,43 @@ void RawCommentList::addComment(const RawComment &RC,
onlyWhitespaceBetween(SourceMgr, C1.getEndLoc(), C2.getBeginLoc(),
/*MaxNewlinesAllowed=*/1)) {
SourceRange MergedRange(C1.getBeginLoc(), C2.getEndLoc());
- *Comments.back() = RawComment(SourceMgr, MergedRange, CommentOpts, true);
+ *OrderedComments[CommentFile].rbegin()->second =
+ RawComment(SourceMgr, MergedRange, CommentOpts, true);
} else {
- Comments.push_back(new (Allocator) RawComment(RC));
+ OrderedComments[CommentFile][CommentOffset] =
+ new (Allocator) RawComment(RC);
}
}
-void RawCommentList::addDeserializedComments(ArrayRef<RawComment *> DeserializedComments) {
- std::vector<RawComment *> MergedComments;
- MergedComments.reserve(Comments.size() + DeserializedComments.size());
+const std::map<unsigned, RawComment *> *
+RawCommentList::getCommentsInFile(FileID File) const {
+ auto CommentsInFile = OrderedComments.find(File);
+ if (CommentsInFile == OrderedComments.end())
+ return nullptr;
+
+ return &CommentsInFile->second;
+}
+
+bool RawCommentList::empty() const { return OrderedComments.empty(); }
+
+unsigned RawCommentList::getCommentBeginLine(RawComment *C, FileID File,
+ unsigned Offset) const {
+ auto Cached = CommentBeginLine.find(C);
+ if (Cached != CommentBeginLine.end())
+ return Cached->second;
+ const unsigned Line = SourceMgr.getLineNumber(File, Offset);
+ CommentBeginLine[C] = Line;
+ return Line;
+}
- std::merge(Comments.begin(), Comments.end(),
- DeserializedComments.begin(), DeserializedComments.end(),
- std::back_inserter(MergedComments),
- BeforeThanCompare<RawComment>(SourceMgr));
- std::swap(Comments, MergedComments);
+unsigned RawCommentList::getCommentEndOffset(RawComment *C) const {
+ auto Cached = CommentEndOffset.find(C);
+ if (Cached != CommentEndOffset.end())
+ return Cached->second;
+ const unsigned Offset =
+ SourceMgr.getDecomposedLoc(C->getSourceRange().getEnd()).second;
+ CommentEndOffset[C] = Offset;
+ return Offset;
}
std::string RawComment::getFormattedText(const SourceManager &SourceMgr,
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 0a4d403106bd..80a1451ac789 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -41,6 +41,7 @@
#include <cstring>
#include <string>
#include <utility>
+#include <type_traits>
using namespace clang;
@@ -83,6 +84,16 @@ const char *Stmt::getStmtClassName() const {
#CLASS " should not be polymorphic!");
#include "clang/AST/StmtNodes.inc"
+// Check that no statement / expression class has a non-trival destructor.
+// Statements and expressions are allocated with the BumpPtrAllocator from
+// ASTContext and therefore their destructor is not executed.
+#define STMT(CLASS, PARENT) \
+ static_assert(std::is_trivially_destructible<CLASS>::value, \
+ #CLASS " should be trivially destructible!");
+// FIXME: InitListExpr is not trivially destructible due to its ASTVector.
+#define INITLISTEXPR(CLASS, PARENT)
+#include "clang/AST/StmtNodes.inc"
+
void Stmt::PrintStats() {
// Ensure the table is primed.
getStmtInfoTableEntry(Stmt::NullStmtClass);
diff --git a/lib/AST/StmtOpenMP.cpp b/lib/AST/StmtOpenMP.cpp
index 4e829897cebe..da1364ebffc4 100644
--- a/lib/AST/StmtOpenMP.cpp
+++ b/lib/AST/StmtOpenMP.cpp
@@ -72,6 +72,25 @@ void OMPLoopDirective::setFinals(ArrayRef<Expr *> A) {
std::copy(A.begin(), A.end(), getFinals().begin());
}
+void OMPLoopDirective::setDependentCounters(ArrayRef<Expr *> A) {
+ assert(
+ A.size() == getCollapsedNumber() &&
+ "Number of dependent counters is not the same as the collapsed number");
+ llvm::copy(A, getDependentCounters().begin());
+}
+
+void OMPLoopDirective::setDependentInits(ArrayRef<Expr *> A) {
+ assert(A.size() == getCollapsedNumber() &&
+ "Number of dependent inits is not the same as the collapsed number");
+ llvm::copy(A, getDependentInits().begin());
+}
+
+void OMPLoopDirective::setFinalsConditions(ArrayRef<Expr *> A) {
+ assert(A.size() == getCollapsedNumber() &&
+ "Number of finals conditions is not the same as the collapsed number");
+ llvm::copy(A, getFinalsConditions().begin());
+}
+
OMPParallelDirective *OMPParallelDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, bool HasCancel) {
@@ -122,6 +141,9 @@ OMPSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -170,6 +192,9 @@ OMPForDirective::Create(const ASTContext &C, SourceLocation StartLoc,
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setHasCancel(HasCancel);
return Dir;
@@ -220,6 +245,9 @@ OMPForSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -383,6 +411,9 @@ OMPParallelForDirective *OMPParallelForDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setHasCancel(HasCancel);
return Dir;
@@ -432,6 +463,9 @@ OMPParallelForSimdDirective *OMPParallelForSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -772,6 +806,9 @@ OMPTargetParallelForDirective *OMPTargetParallelForDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setHasCancel(HasCancel);
return Dir;
@@ -914,6 +951,9 @@ OMPTaskLoopDirective *OMPTaskLoopDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -963,6 +1003,9 @@ OMPTaskLoopSimdDirective *OMPTaskLoopSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -978,6 +1021,167 @@ OMPTaskLoopSimdDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses,
return new (Mem) OMPTaskLoopSimdDirective(CollapsedNum, NumClauses);
}
+OMPMasterTaskLoopDirective *OMPMasterTaskLoopDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPMasterTaskLoopDirective), alignof(OMPClause *));
+ void *Mem = C.Allocate(
+ Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_master_taskloop));
+ OMPMasterTaskLoopDirective *Dir = new (Mem) OMPMasterTaskLoopDirective(
+ StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setIsLastIterVariable(Exprs.IL);
+ Dir->setLowerBoundVariable(Exprs.LB);
+ Dir->setUpperBoundVariable(Exprs.UB);
+ Dir->setStrideVariable(Exprs.ST);
+ Dir->setEnsureUpperBound(Exprs.EUB);
+ Dir->setNextLowerBound(Exprs.NLB);
+ Dir->setNextUpperBound(Exprs.NUB);
+ Dir->setNumIterations(Exprs.NumIterations);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setPrivateCounters(Exprs.PrivateCounters);
+ Dir->setInits(Exprs.Inits);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
+ Dir->setPreInits(Exprs.PreInits);
+ return Dir;
+}
+
+OMPMasterTaskLoopDirective *
+OMPMasterTaskLoopDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum, EmptyShell) {
+ unsigned Size =
+ llvm::alignTo(sizeof(OMPMasterTaskLoopDirective), alignof(OMPClause *));
+ void *Mem = C.Allocate(
+ Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_master_taskloop));
+ return new (Mem) OMPMasterTaskLoopDirective(CollapsedNum, NumClauses);
+}
+
+OMPMasterTaskLoopSimdDirective *OMPMasterTaskLoopSimdDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
+ unsigned Size = llvm::alignTo(sizeof(OMPMasterTaskLoopSimdDirective),
+ alignof(OMPClause *));
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_master_taskloop_simd));
+ auto *Dir = new (Mem) OMPMasterTaskLoopSimdDirective(
+ StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setIsLastIterVariable(Exprs.IL);
+ Dir->setLowerBoundVariable(Exprs.LB);
+ Dir->setUpperBoundVariable(Exprs.UB);
+ Dir->setStrideVariable(Exprs.ST);
+ Dir->setEnsureUpperBound(Exprs.EUB);
+ Dir->setNextLowerBound(Exprs.NLB);
+ Dir->setNextUpperBound(Exprs.NUB);
+ Dir->setNumIterations(Exprs.NumIterations);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setPrivateCounters(Exprs.PrivateCounters);
+ Dir->setInits(Exprs.Inits);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
+ Dir->setPreInits(Exprs.PreInits);
+ return Dir;
+}
+
+OMPMasterTaskLoopSimdDirective *
+OMPMasterTaskLoopSimdDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum, EmptyShell) {
+ unsigned Size = llvm::alignTo(sizeof(OMPMasterTaskLoopSimdDirective),
+ alignof(OMPClause *));
+ void *Mem =
+ C.Allocate(Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_master_taskloop_simd));
+ return new (Mem) OMPMasterTaskLoopSimdDirective(CollapsedNum, NumClauses);
+}
+
+OMPParallelMasterTaskLoopDirective *OMPParallelMasterTaskLoopDirective::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+ unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
+ const HelperExprs &Exprs) {
+ unsigned Size = llvm::alignTo(sizeof(OMPParallelMasterTaskLoopDirective),
+ alignof(OMPClause *));
+ void *Mem = C.Allocate(
+ Size + sizeof(OMPClause *) * Clauses.size() +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_parallel_master_taskloop));
+ auto *Dir = new (Mem) OMPParallelMasterTaskLoopDirective(
+ StartLoc, EndLoc, CollapsedNum, Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ Dir->setIterationVariable(Exprs.IterationVarRef);
+ Dir->setLastIteration(Exprs.LastIteration);
+ Dir->setCalcLastIteration(Exprs.CalcLastIteration);
+ Dir->setPreCond(Exprs.PreCond);
+ Dir->setCond(Exprs.Cond);
+ Dir->setInit(Exprs.Init);
+ Dir->setInc(Exprs.Inc);
+ Dir->setIsLastIterVariable(Exprs.IL);
+ Dir->setLowerBoundVariable(Exprs.LB);
+ Dir->setUpperBoundVariable(Exprs.UB);
+ Dir->setStrideVariable(Exprs.ST);
+ Dir->setEnsureUpperBound(Exprs.EUB);
+ Dir->setNextLowerBound(Exprs.NLB);
+ Dir->setNextUpperBound(Exprs.NUB);
+ Dir->setNumIterations(Exprs.NumIterations);
+ Dir->setCounters(Exprs.Counters);
+ Dir->setPrivateCounters(Exprs.PrivateCounters);
+ Dir->setInits(Exprs.Inits);
+ Dir->setUpdates(Exprs.Updates);
+ Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
+ Dir->setPreInits(Exprs.PreInits);
+ return Dir;
+}
+
+OMPParallelMasterTaskLoopDirective *
+OMPParallelMasterTaskLoopDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ unsigned CollapsedNum,
+ EmptyShell) {
+ unsigned Size = llvm::alignTo(sizeof(OMPParallelMasterTaskLoopDirective),
+ alignof(OMPClause *));
+ void *Mem = C.Allocate(
+ Size + sizeof(OMPClause *) * NumClauses +
+ sizeof(Stmt *) *
+ numLoopChildren(CollapsedNum, OMPD_parallel_master_taskloop));
+ return new (Mem) OMPParallelMasterTaskLoopDirective(CollapsedNum, NumClauses);
+}
+
OMPDistributeDirective *OMPDistributeDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
@@ -1011,6 +1215,9 @@ OMPDistributeDirective *OMPDistributeDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -1089,6 +1296,9 @@ OMPDistributeParallelForDirective *OMPDistributeParallelForDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
@@ -1157,6 +1367,9 @@ OMPDistributeParallelForSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
@@ -1219,6 +1432,9 @@ OMPDistributeSimdDirective *OMPDistributeSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -1271,6 +1487,9 @@ OMPTargetParallelForSimdDirective *OMPTargetParallelForSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -1315,6 +1534,9 @@ OMPTargetSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -1363,6 +1585,9 @@ OMPTeamsDistributeDirective *OMPTeamsDistributeDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -1414,6 +1639,9 @@ OMPTeamsDistributeSimdDirective *OMPTeamsDistributeSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -1471,6 +1699,9 @@ OMPTeamsDistributeParallelForSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
@@ -1540,6 +1771,9 @@ OMPTeamsDistributeParallelForDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
@@ -1628,6 +1862,9 @@ OMPTargetTeamsDistributeDirective *OMPTargetTeamsDistributeDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
@@ -1688,6 +1925,9 @@ OMPTargetTeamsDistributeParallelForDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
@@ -1761,6 +2001,9 @@ OMPTargetTeamsDistributeParallelForSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setCombinedLowerBoundVariable(Exprs.DistCombinedFields.LB);
Dir->setCombinedUpperBoundVariable(Exprs.DistCombinedFields.UB);
@@ -1826,6 +2069,9 @@ OMPTargetTeamsDistributeSimdDirective::Create(
Dir->setInits(Exprs.Inits);
Dir->setUpdates(Exprs.Updates);
Dir->setFinals(Exprs.Finals);
+ Dir->setDependentCounters(Exprs.DependentCounters);
+ Dir->setDependentInits(Exprs.DependentInits);
+ Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
return Dir;
}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 46802d765e1f..7759ff6c1389 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -823,6 +823,24 @@ void StmtPrinter::VisitOMPTaskLoopSimdDirective(
PrintOMPExecutableDirective(Node);
}
+void StmtPrinter::VisitOMPMasterTaskLoopDirective(
+ OMPMasterTaskLoopDirective *Node) {
+ Indent() << "#pragma omp master taskloop";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPMasterTaskLoopSimdDirective(
+ OMPMasterTaskLoopSimdDirective *Node) {
+ Indent() << "#pragma omp master taskloop simd";
+ PrintOMPExecutableDirective(Node);
+}
+
+void StmtPrinter::VisitOMPParallelMasterTaskLoopDirective(
+ OMPParallelMasterTaskLoopDirective *Node) {
+ Indent() << "#pragma omp parallel master taskloop";
+ PrintOMPExecutableDirective(Node);
+}
+
void StmtPrinter::VisitOMPDistributeDirective(OMPDistributeDirective *Node) {
Indent() << "#pragma omp distribute";
PrintOMPExecutableDirective(Node);
@@ -1102,7 +1120,7 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
OS << Node->getValue().toString(10, isSigned);
// Emit suffixes. Integer literals are always a builtin integer type.
- switch (Node->getType()->getAs<BuiltinType>()->getKind()) {
+ switch (Node->getType()->castAs<BuiltinType>()->getKind()) {
default: llvm_unreachable("Unexpected type for integer literal!");
case BuiltinType::Char_S:
case BuiltinType::Char_U: OS << "i8"; break;
@@ -1123,7 +1141,7 @@ void StmtPrinter::VisitFixedPointLiteral(FixedPointLiteral *Node) {
return;
OS << Node->getValueAsString(/*Radix=*/10);
- switch (Node->getType()->getAs<BuiltinType>()->getKind()) {
+ switch (Node->getType()->castAs<BuiltinType>()->getKind()) {
default: llvm_unreachable("Unexpected type for fixed point literal!");
case BuiltinType::ShortFract: OS << "hr"; break;
case BuiltinType::ShortAccum: OS << "hk"; break;
@@ -1152,7 +1170,7 @@ static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node,
return;
// Emit suffixes. Float literals are always a builtin float type.
- switch (Node->getType()->getAs<BuiltinType>()->getKind()) {
+ switch (Node->getType()->castAs<BuiltinType>()->getKind()) {
default: llvm_unreachable("Unexpected type for float literal!");
case BuiltinType::Half: break; // FIXME: suffix?
case BuiltinType::Double: break; // no suffix.
@@ -1679,6 +1697,15 @@ void StmtPrinter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *Node) {
OS << ")";
}
+void StmtPrinter::VisitCXXRewrittenBinaryOperator(
+ CXXRewrittenBinaryOperator *Node) {
+ CXXRewrittenBinaryOperator::DecomposedForm Decomposed =
+ Node->getDecomposedForm();
+ PrintExpr(const_cast<Expr*>(Decomposed.LHS));
+ OS << ' ' << BinaryOperator::getOpcodeStr(Decomposed.Opcode) << ' ';
+ PrintExpr(const_cast<Expr*>(Decomposed.RHS));
+}
+
void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
OS << Node->getCastName() << '<';
Node->getTypeAsWritten().print(OS, Policy);
@@ -1952,7 +1979,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
if (Node->isMutable())
OS << " mutable";
- auto *Proto = Method->getType()->getAs<FunctionProtoType>();
+ auto *Proto = Method->getType()->castAs<FunctionProtoType>();
Proto->printExceptionSpecification(OS, Policy);
// FIXME: Attributes
@@ -2219,6 +2246,17 @@ void StmtPrinter::VisitCXXFoldExpr(CXXFoldExpr *E) {
OS << ")";
}
+void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
+ NestedNameSpecifierLoc NNS = E->getNestedNameSpecifierLoc();
+ if (NNS)
+ NNS.getNestedNameSpecifier()->print(OS, Policy);
+ if (E->getTemplateKWLoc().isValid())
+ OS << "template ";
+ OS << E->getFoundDecl()->getName();
+ printTemplateArgumentList(OS, E->getTemplateArgsAsWritten()->arguments(),
+ Policy);
+}
+
// C++ Coroutines TS
void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index f92c3dc60ba5..d1e856538932 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -440,6 +440,7 @@ void OMPClauseProfiler::VisitOMPIfClause(const OMPIfClause *C) {
}
void OMPClauseProfiler::VisitOMPFinalClause(const OMPFinalClause *C) {
+ VistOMPClauseWithPreInit(C);
if (C->getCondition())
Profiler->VisitStmt(C->getCondition());
}
@@ -736,14 +737,17 @@ void OMPClauseProfiler::VisitOMPThreadLimitClause(
Profiler->VisitStmt(C->getThreadLimit());
}
void OMPClauseProfiler::VisitOMPPriorityClause(const OMPPriorityClause *C) {
+ VistOMPClauseWithPreInit(C);
if (C->getPriority())
Profiler->VisitStmt(C->getPriority());
}
void OMPClauseProfiler::VisitOMPGrainsizeClause(const OMPGrainsizeClause *C) {
+ VistOMPClauseWithPreInit(C);
if (C->getGrainsize())
Profiler->VisitStmt(C->getGrainsize());
}
void OMPClauseProfiler::VisitOMPNumTasksClause(const OMPNumTasksClause *C) {
+ VistOMPClauseWithPreInit(C);
if (C->getNumTasks())
Profiler->VisitStmt(C->getNumTasks());
}
@@ -918,6 +922,21 @@ void StmtProfiler::VisitOMPTaskLoopSimdDirective(
VisitOMPLoopDirective(S);
}
+void StmtProfiler::VisitOMPMasterTaskLoopDirective(
+ const OMPMasterTaskLoopDirective *S) {
+ VisitOMPLoopDirective(S);
+}
+
+void StmtProfiler::VisitOMPMasterTaskLoopSimdDirective(
+ const OMPMasterTaskLoopSimdDirective *S) {
+ VisitOMPLoopDirective(S);
+}
+
+void StmtProfiler::VisitOMPParallelMasterTaskLoopDirective(
+ const OMPParallelMasterTaskLoopDirective *S) {
+ VisitOMPLoopDirective(S);
+}
+
void StmtProfiler::VisitOMPDistributeDirective(
const OMPDistributeDirective *S) {
VisitOMPLoopDirective(S);
@@ -1297,6 +1316,14 @@ void StmtProfiler::VisitAtomicExpr(const AtomicExpr *S) {
ID.AddInteger(S->getOp());
}
+void StmtProfiler::VisitConceptSpecializationExpr(
+ const ConceptSpecializationExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getFoundDecl());
+ VisitTemplateArguments(S->getTemplateArgsAsWritten()->getTemplateArgs(),
+ S->getTemplateArgsAsWritten()->NumTemplateArgs);
+}
+
static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
UnaryOperatorKind &UnaryOp,
BinaryOperatorKind &BinaryOp) {
@@ -1530,6 +1557,16 @@ void StmtProfiler::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
ID.AddInteger(S->getOperator());
}
+void StmtProfiler::VisitCXXRewrittenBinaryOperator(
+ const CXXRewrittenBinaryOperator *S) {
+ // If a rewritten operator were ever to be type-dependent, we should profile
+ // it following its syntactic operator.
+ assert(!S->isTypeDependent() &&
+ "resolved rewritten operator should never be type-dependent");
+ ID.AddBoolean(S->isReversed());
+ VisitExpr(S->getSemanticForm());
+}
+
#if defined(_MSC_VER) && !defined(__clang__)
#if _MSC_VER == 1911
#pragma optimize("", on)
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index cb4cbd2f76a1..db16c2a06b64 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -370,7 +370,7 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
switch (getKind()) {
case Type:
- return getAsType()->getAs<PackExpansionType>()->getPattern();
+ return getAsType()->castAs<PackExpansionType>()->getPattern();
case Expression:
return cast<PackExpansionExpr>(getAsExpr())->getPattern();
diff --git a/lib/AST/TextNodeDumper.cpp b/lib/AST/TextNodeDumper.cpp
index cba9091b1065..63a6510324f7 100644
--- a/lib/AST/TextNodeDumper.cpp
+++ b/lib/AST/TextNodeDumper.cpp
@@ -223,7 +223,6 @@ void TextNodeDumper::Visit(const Decl *D) {
return;
}
- Context = &D->getASTContext();
{
ColorScope Color(OS, ShowColors, DeclKindNameColor);
OS << D->getDeclKindName() << "Decl";
@@ -637,8 +636,8 @@ static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) {
if (!First)
OS << " -> ";
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ const auto *RD =
+ cast<CXXRecordDecl>(Base->getType()->castAs<RecordType>()->getDecl());
if (Base->isVirtual())
OS << "virtual ";
@@ -688,7 +687,7 @@ void TextNodeDumper::VisitConstantExpr(const ConstantExpr *Node) {
if (Node->getResultAPValueKind() != APValue::None) {
ColorScope Color(OS, ShowColors, ValueColor);
OS << " ";
- Node->getAPValueResult().printPretty(OS, *Context, Node->getType());
+ Node->getAPValueResult().dump(OS);
}
}
@@ -1385,6 +1384,8 @@ void TextNodeDumper::VisitVarDecl(const VarDecl *D) {
break;
}
}
+ if (D->needsDestruction(D->getASTContext()))
+ OS << " destroyed";
if (D->isParameterPack())
OS << " pack";
}
@@ -1537,6 +1538,7 @@ void TextNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
FLAG(isGenericLambda, generic);
FLAG(isLambda, lambda);
+ FLAG(isAnonymousStructOrUnion, is_anonymous);
FLAG(canPassInRegisters, pass_in_registers);
FLAG(isEmpty, empty);
FLAG(isAggregate, aggregate);
@@ -1641,6 +1643,7 @@ void TextNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
FLAG(hasTrivialDestructor, trivial);
FLAG(hasNonTrivialDestructor, non_trivial);
FLAG(hasUserDeclaredDestructor, user_declared);
+ FLAG(hasConstexprDestructor, constexpr);
FLAG(needsImplicitDestructor, needs_implicit);
FLAG(needsOverloadResolutionForDestructor, needs_overload_resolution);
if (!D->needsOverloadResolutionForDestructor())
@@ -1766,6 +1769,12 @@ void TextNodeDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
case LinkageSpecDecl::lang_cxx:
OS << " C++";
break;
+ case LinkageSpecDecl::lang_cxx_11:
+ OS << " C++11";
+ break;
+ case LinkageSpecDecl::lang_cxx_14:
+ OS << " C++14";
+ break;
}
}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index ed75a0b5bcd8..4d54ea1061ed 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -50,6 +50,7 @@
#include <cassert>
#include <cstdint>
#include <cstring>
+#include <type_traits>
using namespace clang;
@@ -74,11 +75,11 @@ const IdentifierInfo* QualType::getBaseTypeIdentifier() const {
if (ty->isPointerType() || ty->isReferenceType())
return ty->getPointeeType().getBaseTypeIdentifier();
else if (ty->isRecordType())
- ND = ty->getAs<RecordType>()->getDecl();
+ ND = ty->castAs<RecordType>()->getDecl();
else if (ty->isEnumeralType())
- ND = ty->getAs<EnumType>()->getDecl();
+ ND = ty->castAs<EnumType>()->getDecl();
else if (ty->getTypeClass() == Type::Typedef)
- ND = ty->getAs<TypedefType>()->getDecl();
+ ND = ty->castAs<TypedefType>()->getDecl();
else if (ty->isArrayType())
return ty->castAsArrayTypeUnsafe()->
getElementType().getBaseTypeIdentifier();
@@ -108,6 +109,33 @@ bool QualType::isConstant(QualType T, const ASTContext &Ctx) {
return T.getAddressSpace() == LangAS::opencl_constant;
}
+// C++ [temp.dep.type]p1:
+// A type is dependent if it is...
+// - an array type constructed from any dependent type or whose
+// size is specified by a constant expression that is
+// value-dependent,
+ArrayType::ArrayType(TypeClass tc, QualType et, QualType can,
+ ArraySizeModifier sm, unsigned tq, const Expr *sz)
+ // Note, we need to check for DependentSizedArrayType explicitly here
+ // because we use a DependentSizedArrayType with no size expression as the
+ // type of a dependent array of unknown bound with a dependent braced
+ // initializer:
+ //
+ // template<int ...N> int arr[] = {N...};
+ : Type(tc, can,
+ et->isDependentType() || (sz && sz->isValueDependent()) ||
+ tc == DependentSizedArray,
+ et->isInstantiationDependentType() ||
+ (sz && sz->isInstantiationDependent()) ||
+ tc == DependentSizedArray,
+ (tc == VariableArray || et->isVariablyModifiedType()),
+ et->containsUnexpandedParameterPack() ||
+ (sz && sz->containsUnexpandedParameterPack())),
+ ElementType(et) {
+ ArrayTypeBits.IndexTypeQuals = tq;
+ ArrayTypeBits.SizeModifier = sm;
+}
+
unsigned ConstantArrayType::getNumAddressingBits(const ASTContext &Context,
QualType ElementType,
const llvm::APInt &NumElements) {
@@ -155,14 +183,26 @@ unsigned ConstantArrayType::getMaxSizeBits(const ASTContext &Context) {
return Bits;
}
+void ConstantArrayType::Profile(llvm::FoldingSetNodeID &ID,
+ const ASTContext &Context, QualType ET,
+ const llvm::APInt &ArraySize,
+ const Expr *SizeExpr, ArraySizeModifier SizeMod,
+ unsigned TypeQuals) {
+ ID.AddPointer(ET.getAsOpaquePtr());
+ ID.AddInteger(ArraySize.getZExtValue());
+ ID.AddInteger(SizeMod);
+ ID.AddInteger(TypeQuals);
+ ID.AddBoolean(SizeExpr != 0);
+ if (SizeExpr)
+ SizeExpr->Profile(ID, Context, true);
+}
+
DependentSizedArrayType::DependentSizedArrayType(const ASTContext &Context,
QualType et, QualType can,
Expr *e, ArraySizeModifier sm,
unsigned tq,
SourceRange brackets)
- : ArrayType(DependentSizedArray, et, can, sm, tq,
- (et->containsUnexpandedParameterPack() ||
- (e && e->containsUnexpandedParameterPack()))),
+ : ArrayType(DependentSizedArray, et, can, sm, tq, e),
Context(Context), SizeExpr((Stmt*) e), Brackets(brackets) {}
void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID,
@@ -297,7 +337,19 @@ QualType QualType::getSingleStepDesugaredTypeImpl(QualType type,
#define TYPE(CLASS, BASE) \
static_assert(!std::is_polymorphic<CLASS##Type>::value, \
#CLASS "Type should not be polymorphic!");
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
+
+// Check that no type class has a non-trival destructor. Types are
+// allocated with the BumpPtrAllocator from ASTContext and therefore
+// their destructor is not executed.
+//
+// FIXME: ConstantArrayType is not trivially destructible because of its
+// APInt member. It should be replaced in favor of ASTContext allocation.
+#define TYPE(CLASS, BASE) \
+ static_assert(std::is_trivially_destructible<CLASS##Type>::value || \
+ std::is_same<CLASS##Type, ConstantArrayType>::value, \
+ #CLASS "Type should be trivially destructible!");
+#include "clang/AST/TypeNodes.inc"
QualType Type::getLocallyUnqualifiedSingleStepDesugaredType() const {
switch (getTypeClass()) {
@@ -308,7 +360,7 @@ QualType Type::getLocallyUnqualifiedSingleStepDesugaredType() const {
if (!ty->isSugared()) return QualType(ty, 0); \
return ty->desugar(); \
}
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
llvm_unreachable("bad type kind!");
}
@@ -329,7 +381,7 @@ SplitQualType QualType::getSplitDesugaredType(QualType T) {
Cur = Ty->desugar(); \
break; \
}
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
}
}
@@ -357,7 +409,7 @@ SplitQualType QualType::getSplitUnqualifiedTypeImpl(QualType type) {
next = ty->desugar(); \
break; \
}
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
// Otherwise, split the underlying type. If that yields qualifiers,
@@ -396,7 +448,7 @@ template<typename T> static const T *getAsSugar(const Type *Cur) {
Cur = Ty->desugar().getTypePtr(); \
break; \
}
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
}
}
@@ -429,7 +481,7 @@ const Type *Type::getUnqualifiedDesugaredType() const {
Cur = Ty->desugar().getTypePtr(); \
break; \
}
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
}
}
@@ -611,6 +663,10 @@ ObjCTypeParamType::ObjCTypeParamType(const ObjCTypeParamDecl *D,
initialize(protocols);
}
+QualType ObjCTypeParamType::desugar() const {
+ return getDecl()->getUnderlyingType();
+}
+
ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
ArrayRef<QualType> typeArgs,
ArrayRef<ObjCProtocolDecl *> protocols,
@@ -753,7 +809,7 @@ public:
#define TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base) \
QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); }
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
#define TRIVIAL_TYPE_CLASS(Class) \
QualType Visit##Class##Type(const Class##Type *T) { return QualType(T, 0); }
@@ -847,7 +903,7 @@ public:
if (elementType.getAsOpaquePtr() == T->getElementType().getAsOpaquePtr())
return QualType(T, 0);
- return Ctx.getConstantArrayType(elementType, T->getSize(),
+ return Ctx.getConstantArrayType(elementType, T->getSize(), T->getSizeExpr(),
T->getSizeModifier(),
T->getIndexTypeCVRQualifiers());
}
@@ -2477,6 +2533,15 @@ bool QualType::isCXX11PODType(const ASTContext &Context) const {
return false;
}
+bool Type::isNothrowT() const {
+ if (const auto *RD = getAsCXXRecordDecl()) {
+ IdentifierInfo *II = RD->getIdentifier();
+ if (II && II->isStr("nothrow_t") && RD->isInStdNamespace())
+ return true;
+ }
+ return false;
+}
+
bool Type::isAlignValT() const {
if (const auto *ET = getAs<EnumType>()) {
IdentifierInfo *II = ET->getDecl()->getIdentifier();
@@ -2690,7 +2755,7 @@ const char *Type::getTypeClassName() const {
switch (TypeBits.TC) {
#define ABSTRACT_TYPE(Derived, Base)
#define TYPE(Derived, Base) case Derived: return #Derived;
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
llvm_unreachable("Invalid type class.");
@@ -2841,6 +2906,10 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
case Id: \
return #ExtType;
#include "clang/Basic/OpenCLExtensionTypes.def"
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case Id: \
+ return Name;
+#include "clang/Basic/AArch64SVEACLETypes.def"
}
llvm_unreachable("Invalid builtin type.");
@@ -3556,14 +3625,15 @@ static CachedProperties computeCachedProperties(const Type *T) {
switch (T->getTypeClass()) {
#define TYPE(Class,Base)
#define NON_CANONICAL_TYPE(Class,Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("didn't expect a non-canonical type here");
#define TYPE(Class,Base)
#define DEPENDENT_TYPE(Class,Base) case Type::Class:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class,Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
// Treat instantiation-dependent types as external.
+ if (!T->isInstantiationDependentType()) T->dump();
assert(T->isInstantiationDependentType());
return CachedProperties(ExternalLinkage, false);
@@ -3659,13 +3729,13 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) {
switch (T->getTypeClass()) {
#define TYPE(Class,Base)
#define NON_CANONICAL_TYPE(Class,Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("didn't expect a non-canonical type here");
#define TYPE(Class,Base)
#define DEPENDENT_TYPE(Class,Base) case Type::Class:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class,Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
// Treat instantiation-dependent types as external.
assert(T->isInstantiationDependentType());
return LinkageInfo::external();
@@ -3774,7 +3844,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
case Type::Class: \
llvm_unreachable("non-canonical type");
#define TYPE(Class, Parent)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
// Pointer types.
case Type::Pointer:
@@ -3842,6 +3912,9 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
case BuiltinType::OCLReserveID:
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
case BuiltinType::BuiltinFn:
case BuiltinType::NullPtr:
case BuiltinType::OMPArraySection:
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index abe4c4eb25e6..e4788f32b265 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -391,6 +391,9 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
case BuiltinType::OCLReserveID:
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
case BuiltinType::BuiltinFn:
case BuiltinType::OMPArraySection:
return TST_unspecified;
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 8d5c37299e5f..dacbf9a96d81 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -125,7 +125,7 @@ namespace {
#define TYPE(CLASS, PARENT) \
void print##CLASS##Before(const CLASS##Type *T, raw_ostream &OS); \
void print##CLASS##After(const CLASS##Type *T, raw_ostream &OS);
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
private:
void printBefore(const Type *ty, Qualifiers qs, raw_ostream &OS);
@@ -321,7 +321,7 @@ void TypePrinter::printBefore(const Type *T,Qualifiers Quals, raw_ostream &OS) {
#define TYPE(CLASS, PARENT) case Type::CLASS: \
print##CLASS##Before(cast<CLASS##Type>(T), OS); \
break;
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
if (hasAfterQuals) {
@@ -347,7 +347,7 @@ void TypePrinter::printAfter(const Type *T, Qualifiers Quals, raw_ostream &OS) {
#define TYPE(CLASS, PARENT) case Type::CLASS: \
print##CLASS##After(cast<CLASS##Type>(T), OS); \
break;
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
}
@@ -1204,7 +1204,8 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {
// arguments.
if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
ArrayRef<TemplateArgument> Args;
- if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) {
+ TypeSourceInfo *TAW = Spec->getTypeAsWritten();
+ if (!Policy.PrintCanonicalTypes && TAW) {
const TemplateSpecializationType *TST =
cast<TemplateSpecializationType>(TAW->getType());
Args = TST->template_arguments();
@@ -1537,7 +1538,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
QualType t = T->getEquivalentType();
while (!t->isFunctionType())
t = t->getPointeeType();
- OS << (t->getAs<FunctionType>()->getCallConv() == CC_AAPCS ?
+ OS << (t->castAs<FunctionType>()->getCallConv() == CC_AAPCS ?
"\"aapcs\"" : "\"aapcs-vfp\"");
OS << ')';
break;
diff --git a/lib/AST/VTTBuilder.cpp b/lib/AST/VTTBuilder.cpp
index 53d0ef09f14c..d58e87517785 100644
--- a/lib/AST/VTTBuilder.cpp
+++ b/lib/AST/VTTBuilder.cpp
@@ -64,8 +64,8 @@ void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
if (I.isVirtual())
continue;
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const auto *BaseDecl =
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
CharUnits BaseOffset = Base.getBaseOffset() +
@@ -90,8 +90,8 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
return;
for (const auto &I : RD->bases()) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const auto *BaseDecl =
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
// Itanium C++ ABI 2.6.2:
// Secondary virtual pointers are present for all bases with either
@@ -154,8 +154,8 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
VisitedVirtualBasesSetTy &VBases) {
for (const auto &I : RD->bases()) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const auto *BaseDecl =
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
// Check if this is a virtual base.
if (I.isVirtual()) {
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index 0c699571555d..5688042dadd9 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -2268,7 +2268,7 @@ CreateVTableLayout(const ItaniumVTableBuilder &Builder) {
SmallVector<VTableLayout::VTableThunkTy, 1>
VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
- return llvm::make_unique<VTableLayout>(
+ return std::make_unique<VTableLayout>(
Builder.VTableIndices, Builder.vtable_components(), VTableThunks,
Builder.getAddressPoints());
}
@@ -3253,7 +3253,7 @@ void MicrosoftVTableContext::computeVTablePaths(bool ForVBTables,
// Base case: this subobject has its own vptr.
if (ForVBTables ? Layout.hasOwnVBPtr() : Layout.hasOwnVFPtr())
- Paths.push_back(llvm::make_unique<VPtrInfo>(RD));
+ Paths.push_back(std::make_unique<VPtrInfo>(RD));
// Recursive case: get all the vbtables from our bases and remove anything
// that shares a virtual base.
@@ -3276,7 +3276,7 @@ void MicrosoftVTableContext::computeVTablePaths(bool ForVBTables,
continue;
// Copy the path and adjust it as necessary.
- auto P = llvm::make_unique<VPtrInfo>(*BaseInfo);
+ auto P = std::make_unique<VPtrInfo>(*BaseInfo);
// We mangle Base into the path if the path would've been ambiguous and it
// wasn't already extended with Base.
@@ -3562,7 +3562,7 @@ void MicrosoftVTableContext::computeVTableRelatedInformation(
const VTableLayout::AddressPointsMapTy EmptyAddressPointsMap;
{
- auto VFPtrs = llvm::make_unique<VPtrInfoVector>();
+ auto VFPtrs = std::make_unique<VPtrInfoVector>();
computeVTablePaths(/*ForVBTables=*/false, RD, *VFPtrs);
computeFullPathsForVFTables(Context, RD, *VFPtrs);
VFPtrLocations[RD] = std::move(VFPtrs);
@@ -3576,7 +3576,7 @@ void MicrosoftVTableContext::computeVTableRelatedInformation(
assert(VFTableLayouts.count(id) == 0);
SmallVector<VTableLayout::VTableThunkTy, 1> VTableThunks(
Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
- VFTableLayouts[id] = llvm::make_unique<VTableLayout>(
+ VFTableLayouts[id] = std::make_unique<VTableLayout>(
ArrayRef<size_t>{0}, Builder.vtable_components(), VTableThunks,
EmptyAddressPointsMap);
Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
@@ -3668,7 +3668,7 @@ const VirtualBaseInfo &MicrosoftVTableContext::computeVBTableRelatedInformation(
std::unique_ptr<VirtualBaseInfo> &Entry = VBaseInfo[RD];
if (Entry)
return *Entry;
- Entry = llvm::make_unique<VirtualBaseInfo>();
+ Entry = std::make_unique<VirtualBaseInfo>();
VBI = Entry.get();
}
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
index f407e0875ac4..c51fd630e64b 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -374,6 +374,12 @@ public:
return true;
}
+ bool VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
+ const ObjCInterfaceDecl *InterfaceDecl = CAD->getClassInterface();
+ CompatibleAliases[InterfaceDecl].insert(CAD);
+ return true;
+ }
+
bool TraverseDecl(Decl *DeclNode);
bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr);
bool TraverseType(QualType TypeNode);
@@ -430,7 +436,13 @@ public:
bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
const Matcher<NamedDecl> &Base,
- BoundNodesTreeBuilder *Builder) override;
+ BoundNodesTreeBuilder *Builder,
+ bool Directly) override;
+
+ bool objcClassIsDerivedFrom(const ObjCInterfaceDecl *Declaration,
+ const Matcher<NamedDecl> &Base,
+ BoundNodesTreeBuilder *Builder,
+ bool Directly) override;
// Implements ASTMatchFinder::matchesChildOf.
bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
@@ -762,6 +774,23 @@ private:
return false;
}
+ bool
+ objcClassHasMatchingCompatibilityAlias(const ObjCInterfaceDecl *InterfaceDecl,
+ const Matcher<NamedDecl> &Matcher,
+ BoundNodesTreeBuilder *Builder) {
+ auto Aliases = CompatibleAliases.find(InterfaceDecl);
+ if (Aliases == CompatibleAliases.end())
+ return false;
+ for (const ObjCCompatibleAliasDecl *Alias : Aliases->second) {
+ BoundNodesTreeBuilder Result(*Builder);
+ if (Matcher.matches(*Alias, this, &Result)) {
+ *Builder = std::move(Result);
+ return true;
+ }
+ }
+ return false;
+ }
+
/// Bucket to record map.
///
/// Used to get the appropriate bucket for each matcher.
@@ -786,6 +815,11 @@ private:
// Maps a canonical type to its TypedefDecls.
llvm::DenseMap<const Type*, std::set<const TypedefNameDecl*> > TypeAliases;
+ // Maps an Objective-C interface to its ObjCCompatibleAliasDecls.
+ llvm::DenseMap<const ObjCInterfaceDecl *,
+ llvm::SmallPtrSet<const ObjCCompatibleAliasDecl *, 2>>
+ CompatibleAliases;
+
// Maps (matcher, node) -> the match result for memoization.
typedef std::map<MatchKey, MemoizedMatchResult> MemoizationMap;
MemoizationMap ResultCache;
@@ -812,12 +846,13 @@ getAsCXXRecordDeclOrPrimaryTemplate(const Type *TypeNode) {
return nullptr;
}
-// Returns true if the given class is directly or indirectly derived
+// Returns true if the given C++ class is directly or indirectly derived
// from a base type with the given name. A class is not considered to be
// derived from itself.
bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
const Matcher<NamedDecl> &Base,
- BoundNodesTreeBuilder *Builder) {
+ BoundNodesTreeBuilder *Builder,
+ bool Directly) {
if (!Declaration->hasDefinition())
return false;
for (const auto &It : Declaration->bases()) {
@@ -842,12 +877,40 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
*Builder = std::move(Result);
return true;
}
- if (classIsDerivedFrom(ClassDecl, Base, Builder))
+ if (!Directly && classIsDerivedFrom(ClassDecl, Base, Builder, Directly))
return true;
}
return false;
}
+// Returns true if the given Objective-C class is directly or indirectly
+// derived from a matching base class. A class is not considered to be derived
+// from itself.
+bool MatchASTVisitor::objcClassIsDerivedFrom(
+ const ObjCInterfaceDecl *Declaration, const Matcher<NamedDecl> &Base,
+ BoundNodesTreeBuilder *Builder, bool Directly) {
+ // Check if any of the superclasses of the class match.
+ for (const ObjCInterfaceDecl *ClassDecl = Declaration->getSuperClass();
+ ClassDecl != nullptr; ClassDecl = ClassDecl->getSuperClass()) {
+ // Check if there are any matching compatibility aliases.
+ if (objcClassHasMatchingCompatibilityAlias(ClassDecl, Base, Builder))
+ return true;
+
+ // Check if there are any matching type aliases.
+ const Type *TypeNode = ClassDecl->getTypeForDecl();
+ if (typeHasMatchingAlias(TypeNode, Base, Builder))
+ return true;
+
+ if (Base.matches(*ClassDecl, this, Builder))
+ return true;
+
+ if (Directly)
+ return false;
+ }
+
+ return false;
+}
+
bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) {
if (!DeclNode) {
return true;
@@ -1015,7 +1078,7 @@ bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
}
std::unique_ptr<ASTConsumer> MatchFinder::newASTConsumer() {
- return llvm::make_unique<internal::MatchASTConsumer>(this, ParsingDone);
+ return std::make_unique<internal::MatchASTConsumer>(this, ParsingDone);
}
void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node,
diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h
index fac2fc98e09c..9f46108d1848 100644
--- a/lib/ASTMatchers/Dynamic/Marshallers.h
+++ b/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -729,7 +729,7 @@ std::unique_ptr<MatcherDescriptor>
makeMatcherAutoMarshall(ReturnType (*Func)(), StringRef MatcherName) {
std::vector<ast_type_traits::ASTNodeKind> RetTypes;
BuildReturnTypeVector<ReturnType>::build(RetTypes);
- return llvm::make_unique<FixedArgCountMatcherDescriptor>(
+ return std::make_unique<FixedArgCountMatcherDescriptor>(
matcherMarshall0<ReturnType>, reinterpret_cast<void (*)()>(Func),
MatcherName, RetTypes, None);
}
@@ -741,7 +741,7 @@ makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1), StringRef MatcherName) {
std::vector<ast_type_traits::ASTNodeKind> RetTypes;
BuildReturnTypeVector<ReturnType>::build(RetTypes);
ArgKind AK = ArgTypeTraits<ArgType1>::getKind();
- return llvm::make_unique<FixedArgCountMatcherDescriptor>(
+ return std::make_unique<FixedArgCountMatcherDescriptor>(
matcherMarshall1<ReturnType, ArgType1>,
reinterpret_cast<void (*)()>(Func), MatcherName, RetTypes, AK);
}
@@ -755,7 +755,7 @@ makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1, ArgType2),
BuildReturnTypeVector<ReturnType>::build(RetTypes);
ArgKind AKs[] = { ArgTypeTraits<ArgType1>::getKind(),
ArgTypeTraits<ArgType2>::getKind() };
- return llvm::make_unique<FixedArgCountMatcherDescriptor>(
+ return std::make_unique<FixedArgCountMatcherDescriptor>(
matcherMarshall2<ReturnType, ArgType1, ArgType2>,
reinterpret_cast<void (*)()>(Func), MatcherName, RetTypes, AKs);
}
@@ -766,7 +766,7 @@ template <typename ResultT, typename ArgT,
std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall(
ast_matchers::internal::VariadicFunction<ResultT, ArgT, Func> VarFunc,
StringRef MatcherName) {
- return llvm::make_unique<VariadicFuncMatcherDescriptor>(VarFunc, MatcherName);
+ return std::make_unique<VariadicFuncMatcherDescriptor>(VarFunc, MatcherName);
}
/// Overload for VariadicDynCastAllOfMatchers.
@@ -778,7 +778,7 @@ std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall(
ast_matchers::internal::VariadicDynCastAllOfMatcher<BaseT, DerivedT>
VarFunc,
StringRef MatcherName) {
- return llvm::make_unique<DynCastAllOfMatcherDescriptor>(VarFunc, MatcherName);
+ return std::make_unique<DynCastAllOfMatcherDescriptor>(VarFunc, MatcherName);
}
/// Argument adaptative overload.
@@ -791,7 +791,7 @@ std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall(
std::vector<std::unique_ptr<MatcherDescriptor>> Overloads;
AdaptativeOverloadCollector<ArgumentAdapterT, FromTypes, ToTypes>(MatcherName,
Overloads);
- return llvm::make_unique<OverloadedMatcherDescriptor>(Overloads);
+ return std::make_unique<OverloadedMatcherDescriptor>(Overloads);
}
template <template <typename ToArg, typename FromArg> class ArgumentAdapterT,
@@ -810,7 +810,7 @@ std::unique_ptr<MatcherDescriptor> makeMatcherAutoMarshall(
ast_matchers::internal::VariadicOperatorMatcherFunc<MinCount, MaxCount>
Func,
StringRef MatcherName) {
- return llvm::make_unique<VariadicOperatorMatcherDescriptor>(
+ return std::make_unique<VariadicOperatorMatcherDescriptor>(
MinCount, MaxCount, Func.Op, MatcherName);
}
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
index 33058053571a..8c11e069cb05 100644
--- a/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -71,7 +71,7 @@ void RegistryMaps::registerMatcher(
#define REGISTER_MATCHER_OVERLOAD(name) \
registerMatcher(#name, \
- llvm::make_unique<internal::OverloadedMatcherDescriptor>(name##Callbacks))
+ std::make_unique<internal::OverloadedMatcherDescriptor>(name##Callbacks))
#define SPECIFIC_MATCHER_OVERLOAD(name, Id) \
static_cast<::clang::ast_matchers::name##_Type##Id>( \
@@ -108,6 +108,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_OVERLOADED_2(hasType);
REGISTER_OVERLOADED_2(ignoringParens);
REGISTER_OVERLOADED_2(isDerivedFrom);
+ REGISTER_OVERLOADED_2(isDirectlyDerivedFrom);
REGISTER_OVERLOADED_2(isSameOrDerivedFrom);
REGISTER_OVERLOADED_2(loc);
REGISTER_OVERLOADED_2(pointsTo);
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index b6a429ff49eb..9f58b5079c76 100644
--- a/lib/Analysis/AnalysisDeclContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -302,7 +302,7 @@ AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) {
std::unique_ptr<AnalysisDeclContext> &AC = Contexts[D];
if (!AC)
- AC = llvm::make_unique<AnalysisDeclContext>(this, D, cfgBuildOptions);
+ AC = std::make_unique<AnalysisDeclContext>(this, D, cfgBuildOptions);
return AC.get();
}
@@ -310,8 +310,10 @@ BodyFarm &AnalysisDeclContextManager::getBodyFarm() { return FunctionBodyFarm; }
const StackFrameContext *
AnalysisDeclContext::getStackFrame(LocationContext const *Parent, const Stmt *S,
- const CFGBlock *Blk, unsigned Idx) {
- return getLocationContextManager().getStackFrame(this, Parent, S, Blk, Idx);
+ const CFGBlock *Blk, unsigned BlockCount,
+ unsigned Idx) {
+ return getLocationContextManager().getStackFrame(this, Parent, S, Blk,
+ BlockCount, Idx);
}
const BlockInvocationContext *
@@ -359,7 +361,8 @@ void LocationContext::ProfileCommon(llvm::FoldingSetNodeID &ID,
}
void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getAnalysisDeclContext(), getParent(), CallSite, Block, Index);
+ Profile(ID, getAnalysisDeclContext(), getParent(), CallSite, Block,
+ BlockCount, Index);
}
void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) {
@@ -392,18 +395,16 @@ LocationContextManager::getLocationContext(AnalysisDeclContext *ctx,
return L;
}
-const StackFrameContext*
-LocationContextManager::getStackFrame(AnalysisDeclContext *ctx,
- const LocationContext *parent,
- const Stmt *s,
- const CFGBlock *blk, unsigned idx) {
+const StackFrameContext *LocationContextManager::getStackFrame(
+ AnalysisDeclContext *ctx, const LocationContext *parent, const Stmt *s,
+ const CFGBlock *blk, unsigned blockCount, unsigned idx) {
llvm::FoldingSetNodeID ID;
- StackFrameContext::Profile(ID, ctx, parent, s, blk, idx);
+ StackFrameContext::Profile(ID, ctx, parent, s, blk, blockCount, idx);
void *InsertPos;
auto *L =
cast_or_null<StackFrameContext>(Contexts.FindNodeOrInsertPos(ID, InsertPos));
if (!L) {
- L = new StackFrameContext(ctx, parent, s, blk, idx, ++NewID);
+ L = new StackFrameContext(ctx, parent, s, blk, blockCount, idx, ++NewID);
Contexts.InsertNode(L, InsertPos);
}
return L;
diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp
index 576f86516017..43f9e715b3de 100644
--- a/lib/Analysis/BodyFarm.cpp
+++ b/lib/Analysis/BodyFarm.cpp
@@ -408,8 +408,8 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) {
// reference.
for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) {
const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx);
- if (PDecl &&
- CallbackFunctionType->getParamType(ParamIdx - 2)
+ assert(PDecl);
+ if (CallbackFunctionType->getParamType(ParamIdx - 2)
.getNonReferenceType()
.getCanonicalType() !=
PDecl->getType().getNonReferenceType().getCanonicalType()) {
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 0ed1e988a196..a533a8d97b84 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -70,23 +70,47 @@ static SourceLocation GetEndLoc(Decl *D) {
return D->getLocation();
}
+/// Returns true on constant values based around a single IntegerLiteral.
+/// Allow for use of parentheses, integer casts, and negative signs.
+static bool IsIntegerLiteralConstantExpr(const Expr *E) {
+ // Allow parentheses
+ E = E->IgnoreParens();
+
+ // Allow conversions to different integer kind.
+ if (const auto *CE = dyn_cast<CastExpr>(E)) {
+ if (CE->getCastKind() != CK_IntegralCast)
+ return false;
+ E = CE->getSubExpr();
+ }
+
+ // Allow negative numbers.
+ if (const auto *UO = dyn_cast<UnaryOperator>(E)) {
+ if (UO->getOpcode() != UO_Minus)
+ return false;
+ E = UO->getSubExpr();
+ }
+
+ return isa<IntegerLiteral>(E);
+}
+
/// Helper for tryNormalizeBinaryOperator. Attempts to extract an IntegerLiteral
-/// or EnumConstantDecl from the given Expr. If it fails, returns nullptr.
+/// constant expression or EnumConstantDecl from the given Expr. If it fails,
+/// returns nullptr.
static const Expr *tryTransformToIntOrEnumConstant(const Expr *E) {
E = E->IgnoreParens();
- if (isa<IntegerLiteral>(E))
+ if (IsIntegerLiteralConstantExpr(E))
return E;
if (auto *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
return isa<EnumConstantDecl>(DR->getDecl()) ? DR : nullptr;
return nullptr;
}
-/// Tries to interpret a binary operator into `Decl Op Expr` form, if Expr is
-/// an integer literal or an enum constant.
+/// Tries to interpret a binary operator into `Expr Op NumExpr` form, if
+/// NumExpr is an integer literal or an enum constant.
///
/// If this fails, at least one of the returned DeclRefExpr or Expr will be
/// null.
-static std::tuple<const DeclRefExpr *, BinaryOperatorKind, const Expr *>
+static std::tuple<const Expr *, BinaryOperatorKind, const Expr *>
tryNormalizeBinaryOperator(const BinaryOperator *B) {
BinaryOperatorKind Op = B->getOpcode();
@@ -108,8 +132,7 @@ tryNormalizeBinaryOperator(const BinaryOperator *B) {
Constant = tryTransformToIntOrEnumConstant(B->getLHS());
}
- auto *D = dyn_cast<DeclRefExpr>(MaybeDecl->IgnoreParenImpCasts());
- return std::make_tuple(D, Op, Constant);
+ return std::make_tuple(MaybeDecl, Op, Constant);
}
/// For an expression `x == Foo && x == Bar`, this determines whether the
@@ -121,11 +144,11 @@ tryNormalizeBinaryOperator(const BinaryOperator *B) {
static bool areExprTypesCompatible(const Expr *E1, const Expr *E2) {
// User intent isn't clear if they're mixing int literals with enum
// constants.
- if (isa<IntegerLiteral>(E1) != isa<IntegerLiteral>(E2))
+ if (isa<DeclRefExpr>(E1) != isa<DeclRefExpr>(E2))
return false;
// Integer literal comparisons, regardless of literal type, are acceptable.
- if (isa<IntegerLiteral>(E1))
+ if (!isa<DeclRefExpr>(E1))
return true;
// IntegerLiterals are handled above and only EnumConstantDecls are expected
@@ -525,7 +548,7 @@ private:
CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc);
CFGBlock *VisitCaseStmt(CaseStmt *C);
CFGBlock *VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc);
- CFGBlock *VisitCompoundStmt(CompoundStmt *C);
+ CFGBlock *VisitCompoundStmt(CompoundStmt *C, bool ExternallyDestructed);
CFGBlock *VisitConditionalOperator(AbstractConditionalOperator *C,
AddStmtChoice asc);
CFGBlock *VisitContinueStmt(ContinueStmt *C);
@@ -546,7 +569,8 @@ private:
CFGBlock *VisitDeclSubExpr(DeclStmt *DS);
CFGBlock *VisitDefaultStmt(DefaultStmt *D);
CFGBlock *VisitDoStmt(DoStmt *D);
- CFGBlock *VisitExprWithCleanups(ExprWithCleanups *E, AddStmtChoice asc);
+ CFGBlock *VisitExprWithCleanups(ExprWithCleanups *E,
+ AddStmtChoice asc, bool ExternallyDestructed);
CFGBlock *VisitForStmt(ForStmt *F);
CFGBlock *VisitGotoStmt(GotoStmt *G);
CFGBlock *VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc);
@@ -585,7 +609,8 @@ private:
CFGBlock *VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc);
CFGBlock *VisitWhileStmt(WhileStmt *W);
- CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd);
+ CFGBlock *Visit(Stmt *S, AddStmtChoice asc = AddStmtChoice::NotAlwaysAdd,
+ bool ExternallyDestructed = false);
CFGBlock *VisitStmt(Stmt *S, AddStmtChoice asc);
CFGBlock *VisitChildren(Stmt *S);
CFGBlock *VisitNoRecurse(Expr *E, AddStmtChoice asc);
@@ -656,15 +681,17 @@ private:
// Visitors to walk an AST and generate destructors of temporaries in
// full expression.
- CFGBlock *VisitForTemporaryDtors(Stmt *E, bool BindToTemporary,
+ CFGBlock *VisitForTemporaryDtors(Stmt *E, bool ExternallyDestructed,
TempDtorContext &Context);
- CFGBlock *VisitChildrenForTemporaryDtors(Stmt *E, TempDtorContext &Context);
+ CFGBlock *VisitChildrenForTemporaryDtors(Stmt *E, bool ExternallyDestructed,
+ TempDtorContext &Context);
CFGBlock *VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E,
+ bool ExternallyDestructed,
TempDtorContext &Context);
CFGBlock *VisitCXXBindTemporaryExprForTemporaryDtors(
- CXXBindTemporaryExpr *E, bool BindToTemporary, TempDtorContext &Context);
+ CXXBindTemporaryExpr *E, bool ExternallyDestructed, TempDtorContext &Context);
CFGBlock *VisitConditionalOperatorForTemporaryDtors(
- AbstractConditionalOperator *E, bool BindToTemporary,
+ AbstractConditionalOperator *E, bool ExternallyDestructed,
TempDtorContext &Context);
void InsertTempDtorDecisionBlock(const TempDtorContext &Context,
CFGBlock *FalseSucc = nullptr);
@@ -1017,34 +1044,34 @@ private:
if (!LHS->isComparisonOp() || !RHS->isComparisonOp())
return {};
- const DeclRefExpr *Decl1;
- const Expr *Expr1;
+ const Expr *DeclExpr1;
+ const Expr *NumExpr1;
BinaryOperatorKind BO1;
- std::tie(Decl1, BO1, Expr1) = tryNormalizeBinaryOperator(LHS);
+ std::tie(DeclExpr1, BO1, NumExpr1) = tryNormalizeBinaryOperator(LHS);
- if (!Decl1 || !Expr1)
+ if (!DeclExpr1 || !NumExpr1)
return {};
- const DeclRefExpr *Decl2;
- const Expr *Expr2;
+ const Expr *DeclExpr2;
+ const Expr *NumExpr2;
BinaryOperatorKind BO2;
- std::tie(Decl2, BO2, Expr2) = tryNormalizeBinaryOperator(RHS);
+ std::tie(DeclExpr2, BO2, NumExpr2) = tryNormalizeBinaryOperator(RHS);
- if (!Decl2 || !Expr2)
+ if (!DeclExpr2 || !NumExpr2)
return {};
// Check that it is the same variable on both sides.
- if (Decl1->getDecl() != Decl2->getDecl())
+ if (!Expr::isSameComparisonOperand(DeclExpr1, DeclExpr2))
return {};
// Make sure the user's intent is clear (e.g. they're comparing against two
// int literals, or two things from the same enum)
- if (!areExprTypesCompatible(Expr1, Expr2))
+ if (!areExprTypesCompatible(NumExpr1, NumExpr2))
return {};
Expr::EvalResult L1Result, L2Result;
- if (!Expr1->EvaluateAsInt(L1Result, *Context) ||
- !Expr2->EvaluateAsInt(L2Result, *Context))
+ if (!NumExpr1->EvaluateAsInt(L1Result, *Context) ||
+ !NumExpr2->EvaluateAsInt(L2Result, *Context))
return {};
llvm::APSInt L1 = L1Result.Val.getInt();
@@ -1077,6 +1104,10 @@ private:
// * Variable x is equal to the largest literal.
// * Variable x is greater than largest literal.
bool AlwaysTrue = true, AlwaysFalse = true;
+ // Track value of both subexpressions. If either side is always
+ // true/false, another warning should have already been emitted.
+ bool LHSAlwaysTrue = true, LHSAlwaysFalse = true;
+ bool RHSAlwaysTrue = true, RHSAlwaysFalse = true;
for (const llvm::APSInt &Value : Values) {
TryResult Res1, Res2;
Res1 = analyzeLogicOperatorCondition(BO1, Value, L1);
@@ -1092,16 +1123,47 @@ private:
AlwaysTrue &= (Res1.isTrue() || Res2.isTrue());
AlwaysFalse &= !(Res1.isTrue() || Res2.isTrue());
}
+
+ LHSAlwaysTrue &= Res1.isTrue();
+ LHSAlwaysFalse &= Res1.isFalse();
+ RHSAlwaysTrue &= Res2.isTrue();
+ RHSAlwaysFalse &= Res2.isFalse();
}
if (AlwaysTrue || AlwaysFalse) {
- if (BuildOpts.Observer)
+ if (!LHSAlwaysTrue && !LHSAlwaysFalse && !RHSAlwaysTrue &&
+ !RHSAlwaysFalse && BuildOpts.Observer)
BuildOpts.Observer->compareAlwaysTrue(B, AlwaysTrue);
return TryResult(AlwaysTrue);
}
return {};
}
+ /// A bitwise-or with a non-zero constant always evaluates to true.
+ TryResult checkIncorrectBitwiseOrOperator(const BinaryOperator *B) {
+ const Expr *LHSConstant =
+ tryTransformToIntOrEnumConstant(B->getLHS()->IgnoreParenImpCasts());
+ const Expr *RHSConstant =
+ tryTransformToIntOrEnumConstant(B->getRHS()->IgnoreParenImpCasts());
+
+ if ((LHSConstant && RHSConstant) || (!LHSConstant && !RHSConstant))
+ return {};
+
+ const Expr *Constant = LHSConstant ? LHSConstant : RHSConstant;
+
+ Expr::EvalResult Result;
+ if (!Constant->EvaluateAsInt(Result, *Context))
+ return {};
+
+ if (Result.Val.getInt() == 0)
+ return {};
+
+ if (BuildOpts.Observer)
+ BuildOpts.Observer->compareBitwiseOr(B);
+
+ return TryResult(true);
+ }
+
/// Try and evaluate an expression to an integer constant.
bool tryEvaluate(Expr *S, Expr::EvalResult &outResult) {
if (!BuildOpts.PruneTriviallyFalseEdges)
@@ -1119,7 +1181,7 @@ private:
return {};
if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
- if (Bop->isLogicalOp()) {
+ if (Bop->isLogicalOp() || Bop->isEqualityOp()) {
// Check the cache first.
CachedBoolEvalsTy::iterator I = CachedBoolEvals.find(S);
if (I != CachedBoolEvals.end())
@@ -1203,6 +1265,10 @@ private:
TryResult BopRes = checkIncorrectRelationalOperator(Bop);
if (BopRes.isKnown())
return BopRes.isTrue();
+ } else if (Bop->getOpcode() == BO_Or) {
+ TryResult BopRes = checkIncorrectBitwiseOrOperator(Bop);
+ if (BopRes.isKnown())
+ return BopRes.isTrue();
}
}
@@ -1575,7 +1641,7 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
// Generate destructors for temporaries in initialization expression.
TempDtorContext Context;
VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
- /*BindToTemporary=*/false, Context);
+ /*ExternallyDestructed=*/false, Context);
}
}
@@ -2051,7 +2117,8 @@ CFGBuilder::prependAutomaticObjScopeEndWithTerminator(
/// Visit - Walk the subtree of a statement and add extra
/// blocks for ternary operators, &&, and ||. We also process "," and
/// DeclStmts (which may contain nested control-flow).
-CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
+CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc,
+ bool ExternallyDestructed) {
if (!S) {
badCFG = true;
return nullptr;
@@ -2096,7 +2163,7 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
return VisitChooseExpr(cast<ChooseExpr>(S), asc);
case Stmt::CompoundStmtClass:
- return VisitCompoundStmt(cast<CompoundStmt>(S));
+ return VisitCompoundStmt(cast<CompoundStmt>(S), ExternallyDestructed);
case Stmt::ConditionalOperatorClass:
return VisitConditionalOperator(cast<ConditionalOperator>(S), asc);
@@ -2108,7 +2175,8 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
return VisitCXXCatchStmt(cast<CXXCatchStmt>(S));
case Stmt::ExprWithCleanupsClass:
- return VisitExprWithCleanups(cast<ExprWithCleanups>(S), asc);
+ return VisitExprWithCleanups(cast<ExprWithCleanups>(S),
+ asc, ExternallyDestructed);
case Stmt::CXXDefaultArgExprClass:
case Stmt::CXXDefaultInitExprClass:
@@ -2301,6 +2369,9 @@ CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U,
appendStmt(Block, U);
}
+ if (U->getOpcode() == UO_LNot)
+ tryEvaluateBool(U->getSubExpr()->IgnoreParens());
+
return Visit(U->getSubExpr(), AddStmtChoice());
}
@@ -2435,6 +2506,9 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
appendStmt(Block, B);
}
+ if (B->isEqualityOp() || B->isRelationalOp())
+ tryEvaluateBool(B);
+
CFGBlock *RBlock = Visit(B->getRHS());
CFGBlock *LBlock = Visit(B->getLHS());
// If visiting RHS causes us to finish 'Block', e.g. the RHS is a StmtExpr
@@ -2474,10 +2548,8 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
static bool CanThrow(Expr *E, ASTContext &Ctx) {
QualType Ty = E->getType();
- if (Ty->isFunctionPointerType())
- Ty = Ty->getAs<PointerType>()->getPointeeType();
- else if (Ty->isBlockPointerType())
- Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
+ if (Ty->isFunctionPointerType() || Ty->isBlockPointerType())
+ Ty = Ty->getPointeeType();
const FunctionType *FT = Ty->getAs<FunctionType>();
if (FT) {
@@ -2603,7 +2675,7 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
return addStmt(C->getCond());
}
-CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) {
+CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C, bool ExternallyDestructed) {
LocalScope::const_iterator scopeBeginPos = ScopePos;
addLocalScopeForStmt(C);
@@ -2619,11 +2691,16 @@ CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) {
I != E; ++I ) {
// If we hit a segment of code just containing ';' (NullStmts), we can
// get a null block back. In such cases, just use the LastBlock
- if (CFGBlock *newBlock = addStmt(*I))
+ CFGBlock *newBlock = Visit(*I, AddStmtChoice::AlwaysAdd,
+ ExternallyDestructed);
+
+ if (newBlock)
LastBlock = newBlock;
if (badCFG)
return nullptr;
+
+ ExternallyDestructed = false;
}
return LastBlock;
@@ -2766,7 +2843,7 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
// Generate destructors for temporaries in initialization expression.
TempDtorContext Context;
VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(),
- /*BindToTemporary=*/false, Context);
+ /*ExternallyDestructed=*/true, Context);
}
}
@@ -2980,9 +3057,17 @@ CFGBlock *CFGBuilder::VisitReturnStmt(Stmt *S) {
if (!Block->hasNoReturnElement())
addSuccessor(Block, &cfg->getExit());
- // Add the return statement to the block. This may create new blocks if R
- // contains control-flow (short-circuit operations).
- return VisitStmt(S, AddStmtChoice::AlwaysAdd);
+ // Add the return statement to the block.
+ appendStmt(Block, S);
+
+ // Visit children
+ if (ReturnStmt *RS = dyn_cast<ReturnStmt>(S)) {
+ if (Expr *O = RS->getRetValue())
+ return Visit(O, AddStmtChoice::AlwaysAdd, /*ExternallyDestructed=*/true);
+ return Block;
+ } else { // co_return
+ return VisitChildren(S);
+ }
}
CFGBlock *CFGBuilder::VisitSEHExceptStmt(SEHExceptStmt *ES) {
@@ -3014,7 +3099,7 @@ CFGBlock *CFGBuilder::VisitSEHExceptStmt(SEHExceptStmt *ES) {
}
CFGBlock *CFGBuilder::VisitSEHFinallyStmt(SEHFinallyStmt *FS) {
- return VisitCompoundStmt(FS->getBlock());
+ return VisitCompoundStmt(FS->getBlock(), /*ExternallyDestructed=*/false);
}
CFGBlock *CFGBuilder::VisitSEHLeaveStmt(SEHLeaveStmt *LS) {
@@ -3898,7 +3983,7 @@ CFGBlock *CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) {
autoCreateBlock();
appendStmt(Block, SE);
}
- return VisitCompoundStmt(SE->getSubStmt());
+ return VisitCompoundStmt(SE->getSubStmt(), /*ExternallyDestructed=*/true);
}
CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) {
@@ -4363,12 +4448,12 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
}
CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E,
- AddStmtChoice asc) {
+ AddStmtChoice asc, bool ExternallyDestructed) {
if (BuildOpts.AddTemporaryDtors) {
// If adding implicit destructors visit the full expression for adding
// destructors of temporaries.
TempDtorContext Context;
- VisitForTemporaryDtors(E->getSubExpr(), false, Context);
+ VisitForTemporaryDtors(E->getSubExpr(), ExternallyDestructed, Context);
// Full expression has to be added as CFGStmt so it will be sequenced
// before destructors of it's temporaries.
@@ -4477,6 +4562,10 @@ CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E,
autoCreateBlock();
appendStmt(Block, E);
}
+
+ if (E->getCastKind() == CK_IntegralToBoolean)
+ tryEvaluateBool(E->getSubExpr()->IgnoreParens());
+
return Visit(E->getSubExpr(), AddStmtChoice());
}
@@ -4504,7 +4593,7 @@ CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) {
return addStmt(I->getTarget());
}
-CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool BindToTemporary,
+CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool ExternallyDestructed,
TempDtorContext &Context) {
assert(BuildOpts.AddImplicitDtors && BuildOpts.AddTemporaryDtors);
@@ -4515,28 +4604,32 @@ tryAgain:
}
switch (E->getStmtClass()) {
default:
- return VisitChildrenForTemporaryDtors(E, Context);
+ return VisitChildrenForTemporaryDtors(E, false, Context);
+
+ case Stmt::InitListExprClass:
+ return VisitChildrenForTemporaryDtors(E, ExternallyDestructed, Context);
case Stmt::BinaryOperatorClass:
return VisitBinaryOperatorForTemporaryDtors(cast<BinaryOperator>(E),
+ ExternallyDestructed,
Context);
case Stmt::CXXBindTemporaryExprClass:
return VisitCXXBindTemporaryExprForTemporaryDtors(
- cast<CXXBindTemporaryExpr>(E), BindToTemporary, Context);
+ cast<CXXBindTemporaryExpr>(E), ExternallyDestructed, Context);
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass:
return VisitConditionalOperatorForTemporaryDtors(
- cast<AbstractConditionalOperator>(E), BindToTemporary, Context);
+ cast<AbstractConditionalOperator>(E), ExternallyDestructed, Context);
case Stmt::ImplicitCastExprClass:
- // For implicit cast we want BindToTemporary to be passed further.
+ // For implicit cast we want ExternallyDestructed to be passed further.
E = cast<CastExpr>(E)->getSubExpr();
goto tryAgain;
case Stmt::CXXFunctionalCastExprClass:
- // For functional cast we want BindToTemporary to be passed further.
+ // For functional cast we want ExternallyDestructed to be passed further.
E = cast<CXXFunctionalCastExpr>(E)->getSubExpr();
goto tryAgain;
@@ -4550,7 +4643,7 @@ tryAgain:
case Stmt::MaterializeTemporaryExprClass: {
const MaterializeTemporaryExpr* MTE = cast<MaterializeTemporaryExpr>(E);
- BindToTemporary = (MTE->getStorageDuration() != SD_FullExpression);
+ ExternallyDestructed = (MTE->getStorageDuration() != SD_FullExpression);
SmallVector<const Expr *, 2> CommaLHSs;
SmallVector<SubobjectAdjustment, 2> Adjustments;
// Find the expression whose lifetime needs to be extended.
@@ -4561,7 +4654,7 @@ tryAgain:
// Visit the skipped comma operator left-hand sides for other temporaries.
for (const Expr *CommaLHS : CommaLHSs) {
VisitForTemporaryDtors(const_cast<Expr *>(CommaLHS),
- /*BindToTemporary=*/false, Context);
+ /*ExternallyDestructed=*/false, Context);
}
goto tryAgain;
}
@@ -4579,13 +4672,18 @@ tryAgain:
for (Expr *Init : LE->capture_inits()) {
if (Init) {
if (CFGBlock *R = VisitForTemporaryDtors(
- Init, /*BindToTemporary=*/false, Context))
+ Init, /*ExternallyDestructed=*/true, Context))
B = R;
}
}
return B;
}
+ case Stmt::StmtExprClass:
+ // Don't recurse into statement expressions; any cleanups inside them
+ // will be wrapped in their own ExprWithCleanups.
+ return Block;
+
case Stmt::CXXDefaultArgExprClass:
E = cast<CXXDefaultArgExpr>(E)->getExpr();
goto tryAgain;
@@ -4597,6 +4695,7 @@ tryAgain:
}
CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E,
+ bool ExternallyDestructed,
TempDtorContext &Context) {
if (isa<LambdaExpr>(E)) {
// Do not visit the children of lambdas; they have their own CFGs.
@@ -4610,14 +4709,22 @@ CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E,
CFGBlock *B = Block;
for (Stmt *Child : E->children())
if (Child)
- if (CFGBlock *R = VisitForTemporaryDtors(Child, false, Context))
+ if (CFGBlock *R = VisitForTemporaryDtors(Child, ExternallyDestructed, Context))
B = R;
return B;
}
CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(
- BinaryOperator *E, TempDtorContext &Context) {
+ BinaryOperator *E, bool ExternallyDestructed, TempDtorContext &Context) {
+ if (E->isCommaOp()) {
+ // For comma operator LHS expression is visited
+ // before RHS expression. For destructors visit them in reverse order.
+ CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), ExternallyDestructed, Context);
+ CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS(), false, Context);
+ return LHSBlock ? LHSBlock : RHSBlock;
+ }
+
if (E->isLogicalOp()) {
VisitForTemporaryDtors(E->getLHS(), false, Context);
TryResult RHSExecuted = tryEvaluateBool(E->getLHS());
@@ -4652,10 +4759,11 @@ CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(
}
CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
- CXXBindTemporaryExpr *E, bool BindToTemporary, TempDtorContext &Context) {
+ CXXBindTemporaryExpr *E, bool ExternallyDestructed, TempDtorContext &Context) {
// First add destructors for temporaries in subexpression.
- CFGBlock *B = VisitForTemporaryDtors(E->getSubExpr(), false, Context);
- if (!BindToTemporary) {
+ // Because VisitCXXBindTemporaryExpr calls setDestructed:
+ CFGBlock *B = VisitForTemporaryDtors(E->getSubExpr(), true, Context);
+ if (!ExternallyDestructed) {
// If lifetime of temporary is not prolonged (by assigning to constant
// reference) add destructor for it.
@@ -4703,7 +4811,7 @@ void CFGBuilder::InsertTempDtorDecisionBlock(const TempDtorContext &Context,
}
CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
- AbstractConditionalOperator *E, bool BindToTemporary,
+ AbstractConditionalOperator *E, bool ExternallyDestructed,
TempDtorContext &Context) {
VisitForTemporaryDtors(E->getCond(), false, Context);
CFGBlock *ConditionBlock = Block;
@@ -4714,14 +4822,14 @@ CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors(
TempDtorContext TrueContext(
bothKnownTrue(Context.KnownExecuted, ConditionVal));
- VisitForTemporaryDtors(E->getTrueExpr(), BindToTemporary, TrueContext);
+ VisitForTemporaryDtors(E->getTrueExpr(), ExternallyDestructed, TrueContext);
CFGBlock *TrueBlock = Block;
Block = ConditionBlock;
Succ = ConditionSucc;
TempDtorContext FalseContext(
bothKnownTrue(Context.KnownExecuted, NegatedVal));
- VisitForTemporaryDtors(E->getFalseExpr(), BindToTemporary, FalseContext);
+ VisitForTemporaryDtors(E->getFalseExpr(), ExternallyDestructed, FalseContext);
if (TrueContext.TerminatorExpr && FalseContext.TerminatorExpr) {
InsertTempDtorDecisionBlock(FalseContext, TrueBlock);
@@ -4755,7 +4863,8 @@ CFGBlock *CFGBuilder::VisitOMPExecutableDirective(OMPExecutableDirective *D,
}
// Visit associated structured block if any.
if (!D->isStandaloneDirective())
- if (Stmt *S = D->getStructuredBlock()) {
+ if (CapturedStmt *CS = D->getInnermostCapturedStmt()) {
+ Stmt *S = CS->getCapturedStmt();
if (!isa<CompoundStmt>(S))
addLocalScopeAndDtors(S);
if (CFGBlock *R = addStmt(S))
@@ -4867,9 +4976,13 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
while (const ArrayType *arrayType = astContext.getAsArrayType(ty)) {
ty = arrayType->getElementType();
}
- const RecordType *recordType = ty->getAs<RecordType>();
- const CXXRecordDecl *classDecl =
- cast<CXXRecordDecl>(recordType->getDecl());
+
+ // The situation when the type of the lifetime-extending reference
+ // does not correspond to the type of the object is supposed
+ // to be handled by now. In particular, 'ty' is now the unwrapped
+ // record type.
+ const CXXRecordDecl *classDecl = ty->getAsCXXRecordDecl();
+ assert(classDecl);
return classDecl->getDestructor();
}
case CFGElement::DeleteDtor: {
@@ -4894,12 +5007,6 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
llvm_unreachable("getKind() returned bogus value");
}
-bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const {
- if (const CXXDestructorDecl *DD = getDestructorDecl(astContext))
- return DD->isNoReturn();
- return false;
-}
-
//===----------------------------------------------------------------------===//
// CFGBlock operations.
//===----------------------------------------------------------------------===//
@@ -4965,6 +5072,8 @@ class StmtPrinterHelper : public PrinterHelper {
public:
StmtPrinterHelper(const CFG* cfg, const LangOptions &LO)
: LangOpts(LO) {
+ if (!cfg)
+ return;
for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) {
unsigned j = 1;
for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
@@ -5287,9 +5396,21 @@ static void print_construction_context(raw_ostream &OS,
}
static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
+ const CFGElement &E);
+
+void CFGElement::dumpToStream(llvm::raw_ostream &OS) const {
+ StmtPrinterHelper Helper(nullptr, {});
+ print_elem(OS, Helper, *this);
+}
+
+static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
const CFGElement &E) {
- if (Optional<CFGStmt> CS = E.getAs<CFGStmt>()) {
- const Stmt *S = CS->getStmt();
+ switch (E.getKind()) {
+ case CFGElement::Kind::Statement:
+ case CFGElement::Kind::CXXRecordTypedCall:
+ case CFGElement::Kind::Constructor: {
+ CFGStmt CS = E.castAs<CFGStmt>();
+ const Stmt *S = CS.getStmt();
assert(S != nullptr && "Expecting non-null Stmt");
// special printing for statement-expressions.
@@ -5341,70 +5462,96 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
// Expressions need a newline.
if (isa<Expr>(S))
OS << '\n';
- } else if (Optional<CFGInitializer> IE = E.getAs<CFGInitializer>()) {
- print_initializer(OS, Helper, IE->getInitializer());
+
+ break;
+ }
+
+ case CFGElement::Kind::Initializer:
+ print_initializer(OS, Helper, E.castAs<CFGInitializer>().getInitializer());
OS << '\n';
- } else if (Optional<CFGAutomaticObjDtor> DE =
- E.getAs<CFGAutomaticObjDtor>()) {
- const VarDecl *VD = DE->getVarDecl();
+ break;
+
+ case CFGElement::Kind::AutomaticObjectDtor: {
+ CFGAutomaticObjDtor DE = E.castAs<CFGAutomaticObjDtor>();
+ const VarDecl *VD = DE.getVarDecl();
Helper.handleDecl(VD, OS);
- ASTContext &ACtx = VD->getASTContext();
QualType T = VD->getType();
if (T->isReferenceType())
T = getReferenceInitTemporaryType(VD->getInit(), nullptr);
- if (const ArrayType *AT = ACtx.getAsArrayType(T))
- T = ACtx.getBaseElementType(AT);
- OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
- OS << " (Implicit destructor)\n";
- } else if (Optional<CFGLifetimeEnds> DE = E.getAs<CFGLifetimeEnds>()) {
- const VarDecl *VD = DE->getVarDecl();
- Helper.handleDecl(VD, OS);
+ OS << ".~";
+ T.getUnqualifiedType().print(OS, PrintingPolicy(Helper.getLangOpts()));
+ OS << "() (Implicit destructor)\n";
+ break;
+ }
+ case CFGElement::Kind::LifetimeEnds:
+ Helper.handleDecl(E.castAs<CFGLifetimeEnds>().getVarDecl(), OS);
OS << " (Lifetime ends)\n";
- } else if (Optional<CFGLoopExit> LE = E.getAs<CFGLoopExit>()) {
- const Stmt *LoopStmt = LE->getLoopStmt();
- OS << LoopStmt->getStmtClassName() << " (LoopExit)\n";
- } else if (Optional<CFGScopeBegin> SB = E.getAs<CFGScopeBegin>()) {
+ break;
+
+ case CFGElement::Kind::LoopExit:
+ OS << E.castAs<CFGLoopExit>().getLoopStmt()->getStmtClassName() << " (LoopExit)\n";
+ break;
+
+ case CFGElement::Kind::ScopeBegin:
OS << "CFGScopeBegin(";
- if (const VarDecl *VD = SB->getVarDecl())
+ if (const VarDecl *VD = E.castAs<CFGScopeBegin>().getVarDecl())
OS << VD->getQualifiedNameAsString();
OS << ")\n";
- } else if (Optional<CFGScopeEnd> SE = E.getAs<CFGScopeEnd>()) {
+ break;
+
+ case CFGElement::Kind::ScopeEnd:
OS << "CFGScopeEnd(";
- if (const VarDecl *VD = SE->getVarDecl())
+ if (const VarDecl *VD = E.castAs<CFGScopeEnd>().getVarDecl())
OS << VD->getQualifiedNameAsString();
OS << ")\n";
- } else if (Optional<CFGNewAllocator> NE = E.getAs<CFGNewAllocator>()) {
+ break;
+
+ case CFGElement::Kind::NewAllocator:
OS << "CFGNewAllocator(";
- if (const CXXNewExpr *AllocExpr = NE->getAllocatorExpr())
+ if (const CXXNewExpr *AllocExpr = E.castAs<CFGNewAllocator>().getAllocatorExpr())
AllocExpr->getType().print(OS, PrintingPolicy(Helper.getLangOpts()));
OS << ")\n";
- } else if (Optional<CFGDeleteDtor> DE = E.getAs<CFGDeleteDtor>()) {
- const CXXRecordDecl *RD = DE->getCXXRecordDecl();
+ break;
+
+ case CFGElement::Kind::DeleteDtor: {
+ CFGDeleteDtor DE = E.castAs<CFGDeleteDtor>();
+ const CXXRecordDecl *RD = DE.getCXXRecordDecl();
if (!RD)
return;
CXXDeleteExpr *DelExpr =
- const_cast<CXXDeleteExpr*>(DE->getDeleteExpr());
+ const_cast<CXXDeleteExpr*>(DE.getDeleteExpr());
Helper.handledStmt(cast<Stmt>(DelExpr->getArgument()), OS);
OS << "->~" << RD->getName().str() << "()";
OS << " (Implicit destructor)\n";
- } else if (Optional<CFGBaseDtor> BE = E.getAs<CFGBaseDtor>()) {
- const CXXBaseSpecifier *BS = BE->getBaseSpecifier();
+ break;
+ }
+
+ case CFGElement::Kind::BaseDtor: {
+ const CXXBaseSpecifier *BS = E.castAs<CFGBaseDtor>().getBaseSpecifier();
OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()";
OS << " (Base object destructor)\n";
- } else if (Optional<CFGMemberDtor> ME = E.getAs<CFGMemberDtor>()) {
- const FieldDecl *FD = ME->getFieldDecl();
+ break;
+ }
+
+ case CFGElement::Kind::MemberDtor: {
+ const FieldDecl *FD = E.castAs<CFGMemberDtor>().getFieldDecl();
const Type *T = FD->getType()->getBaseElementTypeUnsafe();
OS << "this->" << FD->getName();
OS << ".~" << T->getAsCXXRecordDecl()->getName() << "()";
OS << " (Member object destructor)\n";
- } else if (Optional<CFGTemporaryDtor> TE = E.getAs<CFGTemporaryDtor>()) {
- const CXXBindTemporaryExpr *BT = TE->getBindTemporaryExpr();
+ break;
+ }
+
+ case CFGElement::Kind::TemporaryDtor: {
+ const CXXBindTemporaryExpr *BT = E.castAs<CFGTemporaryDtor>().getBindTemporaryExpr();
OS << "~";
BT->getType().print(OS, PrintingPolicy(Helper.getLangOpts()));
OS << "() (Temporary object destructor)\n";
+ break;
+ }
}
}
@@ -5615,6 +5762,10 @@ void CFG::print(raw_ostream &OS, const LangOptions &LO, bool ShowColors) const {
OS.flush();
}
+size_t CFGBlock::getIndexInCFG() const {
+ return llvm::find(*getParent(), this) - getParent()->begin();
+}
+
/// dump - A simply pretty printer of a CFGBlock that outputs to stderr.
void CFGBlock::dump(const CFG* cfg, const LangOptions &LO,
bool ShowColors) const {
@@ -5652,6 +5803,71 @@ void CFGBlock::printTerminatorJson(raw_ostream &Out, const LangOptions &LO,
Out << JsonFormat(TempOut.str(), AddQuotes);
}
+// Returns true if by simply looking at the block, we can be sure that it
+// results in a sink during analysis. This is useful to know when the analysis
+// was interrupted, and we try to figure out if it would sink eventually.
+// There may be many more reasons why a sink would appear during analysis
+// (eg. checkers may generate sinks arbitrarily), but here we only consider
+// sinks that would be obvious by looking at the CFG.
+static bool isImmediateSinkBlock(const CFGBlock *Blk) {
+ if (Blk->hasNoReturnElement())
+ return true;
+
+ // FIXME: Throw-expressions are currently generating sinks during analysis:
+ // they're not supported yet, and also often used for actually terminating
+ // the program. So we should treat them as sinks in this analysis as well,
+ // at least for now, but once we have better support for exceptions,
+ // we'd need to carefully handle the case when the throw is being
+ // immediately caught.
+ if (std::any_of(Blk->begin(), Blk->end(), [](const CFGElement &Elm) {
+ if (Optional<CFGStmt> StmtElm = Elm.getAs<CFGStmt>())
+ if (isa<CXXThrowExpr>(StmtElm->getStmt()))
+ return true;
+ return false;
+ }))
+ return true;
+
+ return false;
+}
+
+bool CFGBlock::isInevitablySinking() const {
+ const CFG &Cfg = *getParent();
+
+ const CFGBlock *StartBlk = this;
+ if (isImmediateSinkBlock(StartBlk))
+ return true;
+
+ llvm::SmallVector<const CFGBlock *, 32> DFSWorkList;
+ llvm::SmallPtrSet<const CFGBlock *, 32> Visited;
+
+ DFSWorkList.push_back(StartBlk);
+ while (!DFSWorkList.empty()) {
+ const CFGBlock *Blk = DFSWorkList.back();
+ DFSWorkList.pop_back();
+ Visited.insert(Blk);
+
+ // If at least one path reaches the CFG exit, it means that control is
+ // returned to the caller. For now, say that we are not sure what
+ // happens next. If necessary, this can be improved to analyze
+ // the parent StackFrameContext's call site in a similar manner.
+ if (Blk == &Cfg.getExit())
+ return false;
+
+ for (const auto &Succ : Blk->succs()) {
+ if (const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
+ if (!isImmediateSinkBlock(SuccBlk) && !Visited.count(SuccBlk)) {
+ // If the block has reachable child blocks that aren't no-return,
+ // add them to the worklist.
+ DFSWorkList.push_back(SuccBlk);
+ }
+ }
+ }
+ }
+
+ // Nothing reached the exit. It can only mean one thing: there's no return.
+ return true;
+}
+
const Expr *CFGBlock::getLastCondition() const {
// If the terminator is a temporary dtor or a virtual base, etc, we can't
// retrieve a meaningful condition, bail out.
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
index 7eda80ea0505..76be292dad8d 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Analysis/CallGraph.cpp
@@ -79,6 +79,37 @@ public:
VisitChildren(CE);
}
+ void VisitLambdaExpr(LambdaExpr *LE) {
+ if (FunctionTemplateDecl *FTD = LE->getDependentCallOperator())
+ for (FunctionDecl *FD : FTD->specializations())
+ G->VisitFunctionDecl(FD);
+ else if (CXXMethodDecl *MD = LE->getCallOperator())
+ G->VisitFunctionDecl(MD);
+ }
+
+ void VisitCXXNewExpr(CXXNewExpr *E) {
+ if (FunctionDecl *FD = E->getOperatorNew())
+ addCalledDecl(FD);
+ VisitChildren(E);
+ }
+
+ void VisitCXXConstructExpr(CXXConstructExpr *E) {
+ CXXConstructorDecl *Ctor = E->getConstructor();
+ if (FunctionDecl *Def = Ctor->getDefinition())
+ addCalledDecl(Def);
+ VisitChildren(E);
+ }
+
+ // Include the evaluation of the default argument.
+ void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
+ Visit(E->getExpr());
+ }
+
+ // Include the evaluation of the default initializers in a class.
+ void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
+ Visit(E->getExpr());
+ }
+
// Adds may-call edges for the ObjC message sends.
void VisitObjCMessageExpr(ObjCMessageExpr *ME) {
if (ObjCInterfaceDecl *IDecl = ME->getReceiverInterface()) {
@@ -143,13 +174,20 @@ bool CallGraph::includeInGraph(const Decl *D) {
void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) {
assert(D);
- // Allocate a new node, mark it as root, and process it's calls.
+ // Allocate a new node, mark it as root, and process its calls.
CallGraphNode *Node = getOrInsertNode(D);
// Process all the calls by this function as well.
CGBuilder builder(this, Node);
if (Stmt *Body = D->getBody())
builder.Visit(Body);
+
+ // Include C++ constructor member initializers.
+ if (auto constructor = dyn_cast<CXXConstructorDecl>(D)) {
+ for (CXXCtorInitializer *init : constructor->inits()) {
+ builder.Visit(init->getInit());
+ }
+ }
}
CallGraphNode *CallGraph::getNode(const Decl *F) const {
@@ -166,7 +204,7 @@ CallGraphNode *CallGraph::getOrInsertNode(Decl *F) {
if (Node)
return Node.get();
- Node = llvm::make_unique<CallGraphNode>(F);
+ Node = std::make_unique<CallGraphNode>(F);
// Make Root node a parent of all functions to make sure all are reachable.
if (F)
Root->addCallee(Node.get());
diff --git a/lib/Analysis/CloneDetection.cpp b/lib/Analysis/CloneDetection.cpp
index 74328e8ae67f..30d104165cc5 100644
--- a/lib/Analysis/CloneDetection.cpp
+++ b/lib/Analysis/CloneDetection.cpp
@@ -153,9 +153,8 @@ void OnlyLargestCloneConstraint::constrain(
bool FilenamePatternConstraint::isAutoGenerated(
const CloneDetector::CloneGroup &Group) {
- std::string Error;
if (IgnoredFilesPattern.empty() || Group.empty() ||
- !IgnoredFilesRegex->isValid(Error))
+ !IgnoredFilesRegex->isValid())
return false;
for (const StmtSequence &S : Group) {
diff --git a/lib/Analysis/CocoaConventions.cpp b/lib/Analysis/CocoaConventions.cpp
index b2ef426dead2..571d72e1a841 100644
--- a/lib/Analysis/CocoaConventions.cpp
+++ b/lib/Analysis/CocoaConventions.cpp
@@ -38,8 +38,8 @@ bool cocoa::isRefType(QualType RetTy, StringRef Prefix,
return false;
// Is the type void*?
- const PointerType* PT = RetTy->getAs<PointerType>();
- if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType()))
+ const PointerType* PT = RetTy->castAs<PointerType>();
+ if (!PT || !PT->getPointeeType().getUnqualifiedType()->isVoidType())
return false;
// Does the name start with the prefix?
diff --git a/lib/Analysis/Consumed.cpp b/lib/Analysis/Consumed.cpp
index eee36d9caf7f..cde753e8ec57 100644
--- a/lib/Analysis/Consumed.cpp
+++ b/lib/Analysis/Consumed.cpp
@@ -644,10 +644,10 @@ bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg,
continue;
// Adjust state on the caller side.
- if (isRValueRef(ParamType))
- setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
- else if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>())
+ if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>())
setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT));
+ else if (isRValueRef(ParamType) || isConsumableType(ParamType))
+ setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
else if (isPointerOrRef(ParamType) &&
(!ParamType->getPointeeType().isConstQualified() ||
isSetOnReadPtrType(ParamType)))
@@ -1026,7 +1026,7 @@ void ConsumedBlockInfo::addInfo(
} else if (OwnedStateMap)
Entry = std::move(OwnedStateMap);
else
- Entry = llvm::make_unique<ConsumedStateMap>(*StateMap);
+ Entry = std::make_unique<ConsumedStateMap>(*StateMap);
}
void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
@@ -1058,7 +1058,7 @@ ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
assert(Block && "Block pointer must not be NULL");
auto &Entry = StateMapsArray[Block->getBlockID()];
- return isBackEdgeTarget(Block) ? llvm::make_unique<ConsumedStateMap>(*Entry)
+ return isBackEdgeTarget(Block) ? std::make_unique<ConsumedStateMap>(*Entry)
: std::move(Entry);
}
@@ -1317,7 +1317,7 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
- CurrStates = llvm::make_unique<ConsumedStateMap>();
+ CurrStates = std::make_unique<ConsumedStateMap>();
ConsumedStmtVisitor Visitor(*this, CurrStates.get());
// Add all trackable parameters to the state map.
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/Analysis/PathDiagnostic.cpp
index 54fbd6a5bc49..53235ba07699 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/Analysis/PathDiagnostic.cpp
@@ -10,7 +10,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
@@ -29,9 +29,6 @@
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/None.h"
@@ -53,17 +50,6 @@
using namespace clang;
using namespace ento;
-bool PathDiagnosticMacroPiece::containsEvent() const {
- for (const auto &P : subPieces) {
- if (isa<PathDiagnosticEventPiece>(*P))
- return true;
- if (const auto *MP = dyn_cast<PathDiagnosticMacroPiece>(P.get()))
- if (MP->containsEvent())
- return true;
- }
- return false;
-}
-
static StringRef StripTrailingDots(StringRef s) {
for (StringRef::size_type i = s.size(); i != 0; --i)
if (s[i - 1] != '.')
@@ -131,11 +117,11 @@ void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current,
PathDiagnostic::~PathDiagnostic() = default;
PathDiagnostic::PathDiagnostic(
- StringRef CheckName, const Decl *declWithIssue, StringRef bugtype,
+ StringRef CheckerName, const Decl *declWithIssue, StringRef bugtype,
StringRef verboseDesc, StringRef shortDesc, StringRef category,
PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique,
std::unique_ptr<FilesToLineNumsMap> ExecutedLines)
- : CheckName(CheckName), DeclWithIssue(declWithIssue),
+ : CheckerName(CheckerName), DeclWithIssue(declWithIssue),
BugType(StripTrailingDots(bugtype)),
VerboseDesc(StripTrailingDots(verboseDesc)),
ShortDesc(StripTrailingDots(shortDesc)),
@@ -143,69 +129,6 @@ PathDiagnostic::PathDiagnostic(
UniqueingDecl(DeclToUnique), ExecutedLines(std::move(ExecutedLines)),
path(pathImpl) {}
-static PathDiagnosticCallPiece *
-getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP,
- const SourceManager &SMgr) {
- SourceLocation CallLoc = CP->callEnter.asLocation();
-
- // If the call is within a macro, don't do anything (for now).
- if (CallLoc.isMacroID())
- return nullptr;
-
- assert(AnalysisManager::isInCodeFile(CallLoc, SMgr) &&
- "The call piece should not be in a header file.");
-
- // Check if CP represents a path through a function outside of the main file.
- if (!AnalysisManager::isInCodeFile(CP->callEnterWithin.asLocation(), SMgr))
- return CP;
-
- const PathPieces &Path = CP->path;
- if (Path.empty())
- return nullptr;
-
- // Check if the last piece in the callee path is a call to a function outside
- // of the main file.
- if (auto *CPInner = dyn_cast<PathDiagnosticCallPiece>(Path.back().get()))
- return getFirstStackedCallToHeaderFile(CPInner, SMgr);
-
- // Otherwise, the last piece is in the main file.
- return nullptr;
-}
-
-void PathDiagnostic::resetDiagnosticLocationToMainFile() {
- if (path.empty())
- return;
-
- PathDiagnosticPiece *LastP = path.back().get();
- assert(LastP);
- const SourceManager &SMgr = LastP->getLocation().getManager();
-
- // We only need to check if the report ends inside headers, if the last piece
- // is a call piece.
- if (auto *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
- CP = getFirstStackedCallToHeaderFile(CP, SMgr);
- if (CP) {
- // Mark the piece.
- CP->setAsLastInMainSourceFile();
-
- // Update the path diagnostic message.
- const auto *ND = dyn_cast<NamedDecl>(CP->getCallee());
- if (ND) {
- SmallString<200> buf;
- llvm::raw_svector_ostream os(buf);
- os << " (within a call to '" << ND->getDeclName() << "')";
- appendToDesc(os.str());
- }
-
- // Reset the report containing declaration and location.
- DeclWithIssue = CP->getCaller();
- Loc = CP->getLocation();
-
- return;
- }
- }
-}
-
void PathDiagnosticConsumer::anchor() {}
PathDiagnosticConsumer::~PathDiagnosticConsumer() {
@@ -536,12 +459,12 @@ PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) {
// PathDiagnosticLocation methods.
//===----------------------------------------------------------------------===//
-static SourceLocation getValidSourceLocation(const Stmt* S,
- LocationOrAnalysisDeclContext LAC,
- bool UseEnd = false) {
- SourceLocation L = UseEnd ? S->getEndLoc() : S->getBeginLoc();
- assert(!LAC.isNull() && "A valid LocationContext or AnalysisDeclContext should "
- "be passed to PathDiagnosticLocation upon creation.");
+SourceLocation PathDiagnosticLocation::getValidSourceLocation(
+ const Stmt *S, LocationOrAnalysisDeclContext LAC, bool UseEndOfStatement) {
+ SourceLocation L = UseEndOfStatement ? S->getEndLoc() : S->getBeginLoc();
+ 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
// source code, so find an enclosing statement and use its location.
@@ -571,7 +494,7 @@ static SourceLocation getValidSourceLocation(const Stmt* S,
break;
}
- L = UseEnd ? Parent->getEndLoc() : Parent->getBeginLoc();
+ L = UseEndOfStatement ? Parent->getEndLoc() : Parent->getBeginLoc();
} while (!L.isValid());
}
@@ -772,14 +695,18 @@ PathDiagnosticLocation::create(const ProgramPoint& P,
return PathDiagnosticLocation(
CEB->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng);
} else if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
- CFGElement BlockFront = BE->getBlock()->front();
- if (auto StmtElt = BlockFront.getAs<CFGStmt>()) {
- return PathDiagnosticLocation(StmtElt->getStmt()->getBeginLoc(), SMng);
- } else if (auto NewAllocElt = BlockFront.getAs<CFGNewAllocator>()) {
- return PathDiagnosticLocation(
- NewAllocElt->getAllocatorExpr()->getBeginLoc(), SMng);
+ if (Optional<CFGElement> BlockFront = BE->getFirstElement()) {
+ if (auto StmtElt = BlockFront->getAs<CFGStmt>()) {
+ return PathDiagnosticLocation(StmtElt->getStmt()->getBeginLoc(), SMng);
+ } else if (auto NewAllocElt = BlockFront->getAs<CFGNewAllocator>()) {
+ return PathDiagnosticLocation(
+ NewAllocElt->getAllocatorExpr()->getBeginLoc(), SMng);
+ }
+ llvm_unreachable("Unexpected CFG element at front of block");
}
- llvm_unreachable("Unexpected CFG element at front of block");
+
+ return PathDiagnosticLocation(
+ BE->getBlock()->getTerminatorStmt()->getBeginLoc(), SMng);
} else if (Optional<FunctionExitPoint> FE = P.getAs<FunctionExitPoint>()) {
return PathDiagnosticLocation(FE->getStmt(), SMng,
FE->getLocationContext());
@@ -790,116 +717,6 @@ PathDiagnosticLocation::create(const ProgramPoint& P,
return PathDiagnosticLocation(S, SMng, P.getLocationContext());
}
-static const LocationContext *
-findTopAutosynthesizedParentContext(const LocationContext *LC) {
- assert(LC->getAnalysisDeclContext()->isBodyAutosynthesized());
- const LocationContext *ParentLC = LC->getParent();
- assert(ParentLC && "We don't start analysis from autosynthesized code");
- while (ParentLC->getAnalysisDeclContext()->isBodyAutosynthesized()) {
- LC = ParentLC;
- ParentLC = LC->getParent();
- assert(ParentLC && "We don't start analysis from autosynthesized code");
- }
- return LC;
-}
-
-const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) {
- // We cannot place diagnostics on autosynthesized code.
- // Put them onto the call site through which we jumped into autosynthesized
- // code for the first time.
- const LocationContext *LC = N->getLocationContext();
- if (LC->getAnalysisDeclContext()->isBodyAutosynthesized()) {
- // It must be a stack frame because we only autosynthesize functions.
- return cast<StackFrameContext>(findTopAutosynthesizedParentContext(LC))
- ->getCallSite();
- }
- // Otherwise, see if the node's program point directly points to a statement.
- ProgramPoint P = N->getLocation();
- if (auto SP = P.getAs<StmtPoint>())
- return SP->getStmt();
- if (auto BE = P.getAs<BlockEdge>())
- return BE->getSrc()->getTerminatorStmt();
- if (auto CE = P.getAs<CallEnter>())
- return CE->getCallExpr();
- if (auto CEE = P.getAs<CallExitEnd>())
- return CEE->getCalleeContext()->getCallSite();
- if (auto PIPP = P.getAs<PostInitializer>())
- return PIPP->getInitializer()->getInit();
- if (auto CEB = P.getAs<CallExitBegin>())
- return CEB->getReturnStmt();
- if (auto FEP = P.getAs<FunctionExitPoint>())
- return FEP->getStmt();
-
- return nullptr;
-}
-
-const Stmt *PathDiagnosticLocation::getNextStmt(const ExplodedNode *N) {
- for (N = N->getFirstSucc(); N; N = N->getFirstSucc()) {
- if (const Stmt *S = getStmt(N)) {
- // Check if the statement is '?' or '&&'/'||'. These are "merges",
- // not actual statement points.
- switch (S->getStmtClass()) {
- case Stmt::ChooseExprClass:
- case Stmt::BinaryConditionalOperatorClass:
- case Stmt::ConditionalOperatorClass:
- continue;
- case Stmt::BinaryOperatorClass: {
- BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode();
- if (Op == BO_LAnd || Op == BO_LOr)
- continue;
- break;
- }
- default:
- break;
- }
- // We found the statement, so return it.
- return S;
- }
- }
-
- return nullptr;
-}
-
-PathDiagnosticLocation
- PathDiagnosticLocation::createEndOfPath(const ExplodedNode *N,
- const SourceManager &SM) {
- assert(N && "Cannot create a location with a null node.");
- const Stmt *S = getStmt(N);
- const LocationContext *LC = N->getLocationContext();
-
- if (!S) {
- // If this is an implicit call, return the implicit call point location.
- if (Optional<PreImplicitCall> PIE = N->getLocationAs<PreImplicitCall>())
- return PathDiagnosticLocation(PIE->getLocation(), SM);
- if (auto FE = N->getLocationAs<FunctionExitPoint>()) {
- if (const ReturnStmt *RS = FE->getStmt())
- return PathDiagnosticLocation::createBegin(RS, SM, LC);
- }
- S = getNextStmt(N);
- }
-
- if (S) {
- ProgramPoint P = N->getLocation();
-
- // For member expressions, return the location of the '.' or '->'.
- if (const auto *ME = dyn_cast<MemberExpr>(S))
- return PathDiagnosticLocation::createMemberLoc(ME, SM);
-
- // For binary operators, return the location of the operator.
- if (const auto *B = dyn_cast<BinaryOperator>(S))
- return PathDiagnosticLocation::createOperatorLoc(B, SM);
-
- if (P.getAs<PostStmtPurgeDeadSymbols>())
- return PathDiagnosticLocation::createEnd(S, SM, LC);
-
- if (S->getBeginLoc().isValid())
- return PathDiagnosticLocation(S, SM, LC);
- return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM);
- }
-
- return createDeclEnd(N->getLocationContext(), SM);
-}
-
PathDiagnosticLocation PathDiagnosticLocation::createSingleLocation(
const PathDiagnosticLocation &PDL) {
FullSourceLoc L = PDL.asLocation();
@@ -1313,70 +1130,6 @@ void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const {
ID.AddString(*I);
}
-StackHintGenerator::~StackHintGenerator() = default;
-
-std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
- if (!N)
- return getMessageForSymbolNotFound();
-
- ProgramPoint P = N->getLocation();
- CallExitEnd CExit = P.castAs<CallExitEnd>();
-
- // FIXME: Use CallEvent to abstract this over all calls.
- const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
- const auto *CE = dyn_cast_or_null<CallExpr>(CallSite);
- if (!CE)
- return {};
-
- // Check if one of the parameters are set to the interesting symbol.
- unsigned ArgIndex = 0;
- for (CallExpr::const_arg_iterator I = CE->arg_begin(),
- E = CE->arg_end(); I != E; ++I, ++ArgIndex){
- SVal SV = N->getSVal(*I);
-
- // 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 (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
- // Do not attempt to dereference void*.
- if ((*I)->getType()->isVoidPointerType())
- continue;
- SVal PSV = N->getState()->getSVal(Reg->getRegion());
- SymbolRef AS = PSV.getAsLocSymbol();
- if (AS == Sym) {
- return getMessageForArg(*I, ArgIndex);
- }
- }
- }
-
- // Check if we are returning the interesting symbol.
- SVal SV = N->getSVal(CE);
- SymbolRef RetSym = SV.getAsLocSymbol();
- if (RetSym == Sym) {
- return getMessageForReturn(CE);
- }
-
- return getMessageForSymbolNotFound();
-}
-
-std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
- unsigned ArgIndex) {
- // Printed parameters start at 1, not 0.
- ++ArgIndex;
-
- SmallString<200> buf;
- llvm::raw_svector_ostream os(buf);
-
- os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
- << " parameter";
-
- return os.str();
-}
-
LLVM_DUMP_METHOD void PathPieces::dump() const {
unsigned index = 0;
for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) {
diff --git a/lib/Analysis/ProgramPoint.cpp b/lib/Analysis/ProgramPoint.cpp
index 97e90965d007..0783fbed5315 100644
--- a/lib/Analysis/ProgramPoint.cpp
+++ b/lib/Analysis/ProgramPoint.cpp
@@ -188,7 +188,11 @@ void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {
Out << "Statement\", \"stmt_kind\": \"" << S->getStmtClassName()
<< "\", \"stmt_id\": " << S->getID(Context)
- << ", \"pointer\": \"" << (const void *)S << "\", \"pretty\": ";
+ << ", \"pointer\": \"" << (const void *)S << "\", ";
+ if (const auto *CS = dyn_cast<CastExpr>(S))
+ Out << "\"cast_kind\": \"" << CS->getCastKindName() << "\", ";
+
+ Out << "\"pretty\": ";
S->printJson(Out, nullptr, PP, AddQuotes);
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index 2fea88ea2eff..1dab8e309f59 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -247,7 +247,7 @@ static bool isConfigurationValue(const Stmt *S,
}
case Stmt::UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(S);
- if (UO->getOpcode() != UO_LNot)
+ if (UO->getOpcode() != UO_LNot && UO->getOpcode() != UO_Minus)
return false;
bool SilenceableCondValNotSet =
SilenceableCondVal && SilenceableCondVal->getBegin().isInvalid();
diff --git a/lib/Analysis/RetainSummaryManager.cpp b/lib/Analysis/RetainSummaryManager.cpp
index 132053fd2c24..6f46917b2dfc 100644
--- a/lib/Analysis/RetainSummaryManager.cpp
+++ b/lib/Analysis/RetainSummaryManager.cpp
@@ -504,7 +504,7 @@ RetainSummaryManager::generateSummary(const FunctionDecl *FD,
FName = FName.substr(FName.find_first_not_of('_'));
// Inspect the result type. Strip away any typedefs.
- const auto *FT = FD->getType()->getAs<FunctionType>();
+ const auto *FT = FD->getType()->castAs<FunctionType>();
QualType RetTy = FT->getReturnType();
if (TrackOSObjects)
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index c7b4c4455664..c60954374ce3 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -882,7 +882,7 @@ public:
StringRef DiagKind) const override {
FSet.removeLock(FactMan, Cp);
if (!Cp.negative()) {
- FSet.addLock(FactMan, llvm::make_unique<LockableFactEntry>(
+ FSet.addLock(FactMan, std::make_unique<LockableFactEntry>(
!Cp, LK_Exclusive, UnlockLoc));
}
}
@@ -987,7 +987,7 @@ private:
} else {
FSet.removeLock(FactMan, !Cp);
FSet.addLock(FactMan,
- llvm::make_unique<LockableFactEntry>(Cp, kind, loc));
+ std::make_unique<LockableFactEntry>(Cp, kind, loc));
}
}
@@ -996,7 +996,7 @@ private:
StringRef DiagKind) const {
if (FSet.findLock(FactMan, Cp)) {
FSet.removeLock(FactMan, Cp);
- FSet.addLock(FactMan, llvm::make_unique<LockableFactEntry>(
+ FSet.addLock(FactMan, std::make_unique<LockableFactEntry>(
!Cp, LK_Exclusive, loc));
} else if (Handler) {
Handler->handleUnmatchedUnlock(DiagKind, Cp.toString(), loc);
@@ -1551,11 +1551,11 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
// Add and remove locks.
SourceLocation Loc = Exp->getExprLoc();
for (const auto &ExclusiveLockToAdd : ExclusiveLocksToAdd)
- addLock(Result, llvm::make_unique<LockableFactEntry>(ExclusiveLockToAdd,
+ addLock(Result, std::make_unique<LockableFactEntry>(ExclusiveLockToAdd,
LK_Exclusive, Loc),
CapDiagKind);
for (const auto &SharedLockToAdd : SharedLocksToAdd)
- addLock(Result, llvm::make_unique<LockableFactEntry>(SharedLockToAdd,
+ addLock(Result, std::make_unique<LockableFactEntry>(SharedLockToAdd,
LK_Shared, Loc),
CapDiagKind);
}
@@ -1840,7 +1840,7 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
for (const auto &AssertLock : AssertLocks)
Analyzer->addLock(FSet,
- llvm::make_unique<LockableFactEntry>(
+ std::make_unique<LockableFactEntry>(
AssertLock, LK_Exclusive, Loc, false, true),
ClassifyDiagnostic(A));
break;
@@ -1852,7 +1852,7 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
for (const auto &AssertLock : AssertLocks)
Analyzer->addLock(FSet,
- llvm::make_unique<LockableFactEntry>(
+ std::make_unique<LockableFactEntry>(
AssertLock, LK_Shared, Loc, false, true),
ClassifyDiagnostic(A));
break;
@@ -1864,7 +1864,7 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
for (const auto &AssertLock : AssertLocks)
Analyzer->addLock(FSet,
- llvm::make_unique<LockableFactEntry>(
+ std::make_unique<LockableFactEntry>(
AssertLock,
A->isShared() ? LK_Shared : LK_Exclusive, Loc,
false, true),
@@ -1928,11 +1928,11 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
// Add locks.
for (const auto &M : ExclusiveLocksToAdd)
- Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
+ Analyzer->addLock(FSet, std::make_unique<LockableFactEntry>(
M, LK_Exclusive, Loc, isScopedVar),
CapDiagKind);
for (const auto &M : SharedLocksToAdd)
- Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>(
+ Analyzer->addLock(FSet, std::make_unique<LockableFactEntry>(
M, LK_Shared, Loc, isScopedVar),
CapDiagKind);
@@ -1944,7 +1944,7 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
// FIXME: does this store a pointer to DRE?
CapabilityExpr Scp = Analyzer->SxBuilder.translateAttrExpr(&DRE, nullptr);
- auto ScopedEntry = llvm::make_unique<ScopedLockableFactEntry>(Scp, MLoc);
+ auto ScopedEntry = std::make_unique<ScopedLockableFactEntry>(Scp, MLoc);
for (const auto &M : ExclusiveLocksToAdd)
ScopedEntry->addExclusiveLock(M);
for (const auto &M : ScopedExclusiveReqs)
@@ -2349,12 +2349,12 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
// FIXME -- Loc can be wrong here.
for (const auto &Mu : ExclusiveLocksToAdd) {
- auto Entry = llvm::make_unique<LockableFactEntry>(Mu, LK_Exclusive, Loc);
+ auto Entry = std::make_unique<LockableFactEntry>(Mu, LK_Exclusive, Loc);
Entry->setDeclared(true);
addLock(InitialLockset, std::move(Entry), CapDiagKind, true);
}
for (const auto &Mu : SharedLocksToAdd) {
- auto Entry = llvm::make_unique<LockableFactEntry>(Mu, LK_Shared, Loc);
+ auto Entry = std::make_unique<LockableFactEntry>(Mu, LK_Shared, Loc);
Entry->setDeclared(true);
addLock(InitialLockset, std::move(Entry), CapDiagKind, true);
}
@@ -2523,10 +2523,10 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
// issue the appropriate warning.
// FIXME: the location here is not quite right.
for (const auto &Lock : ExclusiveLocksAcquired)
- ExpectedExitSet.addLock(FactMan, llvm::make_unique<LockableFactEntry>(
+ ExpectedExitSet.addLock(FactMan, std::make_unique<LockableFactEntry>(
Lock, LK_Exclusive, D->getLocation()));
for (const auto &Lock : SharedLocksAcquired)
- ExpectedExitSet.addLock(FactMan, llvm::make_unique<LockableFactEntry>(
+ ExpectedExitSet.addLock(FactMan, std::make_unique<LockableFactEntry>(
Lock, LK_Shared, D->getLocation()));
for (const auto &Lock : LocksReleased)
ExpectedExitSet.removeLock(FactMan, Lock);
diff --git a/lib/Analysis/plugins/SampleAnalyzer/MainCallChecker.cpp b/lib/Analysis/plugins/SampleAnalyzer/MainCallChecker.cpp
index 8bd4085108e9..fd210d733fd0 100644
--- a/lib/Analysis/plugins/SampleAnalyzer/MainCallChecker.cpp
+++ b/lib/Analysis/plugins/SampleAnalyzer/MainCallChecker.cpp
@@ -36,8 +36,8 @@ void MainCallChecker::checkPreStmt(const CallExpr *CE,
if (!BT)
BT.reset(new BugType(this, "call to main", "example analyzer plugin"));
- std::unique_ptr<BugReport> report =
- llvm::make_unique<BugReport>(*BT, BT->getName(), N);
+ auto report =
+ std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
report->addRange(Callee->getSourceRange());
C.emitReport(std::move(report));
}
diff --git a/lib/Basic/Attributes.cpp b/lib/Basic/Attributes.cpp
index 9a8eb3d932cc..74cc3d1d03da 100644
--- a/lib/Basic/Attributes.cpp
+++ b/lib/Basic/Attributes.cpp
@@ -1,5 +1,6 @@
#include "clang/Basic/Attributes.h"
#include "clang/Basic/AttrSubjectMatchRules.h"
+#include "clang/Basic/AttributeCommonInfo.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
@@ -21,7 +22,7 @@ int clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope,
#include "clang/Basic/AttrHasAttributeImpl.inc"
- return 0;
+ return 0;
}
const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) {
@@ -33,3 +34,75 @@ const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) {
}
llvm_unreachable("Invalid subject match rule");
}
+
+static StringRef
+normalizeAttrScopeName(StringRef ScopeName,
+ AttributeCommonInfo::Syntax SyntaxUsed) {
+ // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name
+ // to be "clang".
+ if (SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
+ SyntaxUsed == AttributeCommonInfo::AS_C2x) {
+ if (ScopeName == "__gnu__")
+ ScopeName = "gnu";
+ else if (ScopeName == "_Clang")
+ ScopeName = "clang";
+ }
+ return ScopeName;
+}
+
+static StringRef normalizeAttrName(StringRef AttrName,
+ StringRef NormalizedScopeName,
+ AttributeCommonInfo::Syntax SyntaxUsed) {
+ // Normalize the attribute name, __foo__ becomes foo. This is only allowable
+ // for GNU attributes, and attributes using the double square bracket syntax.
+ bool ShouldNormalize =
+ SyntaxUsed == AttributeCommonInfo::AS_GNU ||
+ ((SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
+ SyntaxUsed == AttributeCommonInfo::AS_C2x) &&
+ (NormalizedScopeName.empty() || NormalizedScopeName == "gnu" ||
+ NormalizedScopeName == "clang"));
+ if (ShouldNormalize && AttrName.size() >= 4 && AttrName.startswith("__") &&
+ AttrName.endswith("__"))
+ AttrName = AttrName.slice(2, AttrName.size() - 2);
+
+ return AttrName;
+}
+
+bool AttributeCommonInfo::isGNUScope() const {
+ return ScopeName && (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__"));
+}
+
+#include "clang/Sema/AttrParsedAttrKinds.inc"
+
+AttributeCommonInfo::Kind
+AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name,
+ const IdentifierInfo *ScopeName,
+ Syntax SyntaxUsed) {
+ StringRef AttrName = Name->getName();
+
+ SmallString<64> FullName;
+ if (ScopeName)
+ FullName += normalizeAttrScopeName(ScopeName->getName(), SyntaxUsed);
+
+ AttrName = normalizeAttrName(AttrName, FullName, SyntaxUsed);
+
+ // Ensure that in the case of C++11 attributes, we look for '::foo' if it is
+ // unscoped.
+ if (ScopeName || SyntaxUsed == AS_CXX11 || SyntaxUsed == AS_C2x)
+ FullName += "::";
+ FullName += AttrName;
+
+ return ::getAttrKind(FullName, SyntaxUsed);
+}
+
+unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
+ // Both variables will be used in tablegen generated
+ // attribute spell list index matching code.
+ auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax());
+ StringRef Scope =
+ getScopeName() ? normalizeAttrScopeName(getScopeName()->getName(), Syntax)
+ : "";
+ StringRef Name = normalizeAttrName(getAttrName()->getName(), Scope, Syntax);
+
+#include "clang/Sema/AttrSpellingListIndex.inc"
+}
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index b6a7fde09f35..88a7a1250837 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -18,9 +18,10 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Statistic.h"
#include "llvm/Config/llvm-config.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
@@ -35,6 +36,14 @@
using namespace clang;
+#define DEBUG_TYPE "file-search"
+
+ALWAYS_ENABLED_STATISTIC(NumDirLookups, "Number of directory lookups.");
+ALWAYS_ENABLED_STATISTIC(NumFileLookups, "Number of file lookups.");
+ALWAYS_ENABLED_STATISTIC(NumDirCacheMisses,
+ "Number of directory cache misses.");
+ALWAYS_ENABLED_STATISTIC(NumFileCacheMisses, "Number of file cache misses.");
+
//===----------------------------------------------------------------------===//
// Common logic.
//===----------------------------------------------------------------------===//
@@ -43,9 +52,6 @@ FileManager::FileManager(const FileSystemOptions &FSO,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
: FS(std::move(FS)), FileSystemOpts(FSO), SeenDirEntries(64),
SeenFileEntries(64), NextFileUID(0) {
- NumDirLookups = NumFileLookups = 0;
- NumDirCacheMisses = NumFileCacheMisses = 0;
-
// If the caller doesn't provide a virtual file system, just grab the real
// file system.
if (!this->FS)
@@ -63,14 +69,14 @@ void FileManager::clearStatCache() { StatCache.reset(); }
/// Retrieve the directory that the given file name resides in.
/// Filename can point to either a real file or a virtual file.
-static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
- StringRef Filename,
- bool CacheFailure) {
+static llvm::ErrorOr<const DirectoryEntry *>
+getDirectoryFromFile(FileManager &FileMgr, StringRef Filename,
+ bool CacheFailure) {
if (Filename.empty())
- return nullptr;
+ return std::errc::no_such_file_or_directory;
if (llvm::sys::path::is_separator(Filename[Filename.size() - 1]))
- return nullptr; // If Filename is a directory.
+ return std::errc::is_a_directory;
StringRef DirName = llvm::sys::path::parent_path(Filename);
// Use the current directory if file has no path component.
@@ -87,7 +93,8 @@ void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
if (DirName.empty())
DirName = ".";
- auto &NamedDirEnt = *SeenDirEntries.insert({DirName, nullptr}).first;
+ auto &NamedDirEnt = *SeenDirEntries.insert(
+ {DirName, std::errc::no_such_file_or_directory}).first;
// When caching a virtual directory, we always cache its ancestors
// at the same time. Therefore, if DirName is already in the cache,
@@ -97,17 +104,17 @@ void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
return;
// Add the virtual directory to the cache.
- auto UDE = llvm::make_unique<DirectoryEntry>();
+ auto UDE = std::make_unique<DirectoryEntry>();
UDE->Name = NamedDirEnt.first();
- NamedDirEnt.second = UDE.get();
+ NamedDirEnt.second = *UDE.get();
VirtualDirectoryEntries.push_back(std::move(UDE));
// Recursively add the other ancestors.
addAncestorsAsVirtualDirs(DirName);
}
-const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
- bool CacheFailure) {
+llvm::Expected<DirectoryEntryRef>
+FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) {
// stat doesn't like trailing separators except for root directory.
// At least, on Win32 MSVCRT, stat() cannot strip trailing '/'.
// (though it can strip '\\')
@@ -130,9 +137,13 @@ const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
// See if there was already an entry in the map. Note that the map
// contains both virtual and real directories.
- auto SeenDirInsertResult = SeenDirEntries.insert({DirName, nullptr});
- if (!SeenDirInsertResult.second)
- return SeenDirInsertResult.first->second;
+ auto SeenDirInsertResult =
+ SeenDirEntries.insert({DirName, std::errc::no_such_file_or_directory});
+ if (!SeenDirInsertResult.second) {
+ if (SeenDirInsertResult.first->second)
+ return DirectoryEntryRef(&*SeenDirInsertResult.first);
+ return llvm::errorCodeToError(SeenDirInsertResult.first->second.getError());
+ }
// We've not seen this before. Fill it in.
++NumDirCacheMisses;
@@ -145,11 +156,15 @@ const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
// Check to see if the directory exists.
llvm::vfs::Status Status;
- if (getStatValue(InterndDirName, Status, false, nullptr /*directory lookup*/)) {
+ auto statError = getStatValue(InterndDirName, Status, false,
+ nullptr /*directory lookup*/);
+ if (statError) {
// There's no real directory at the given path.
- if (!CacheFailure)
+ if (CacheFailure)
+ NamedDirEnt.second = statError;
+ else
SeenDirEntries.erase(DirName);
- return nullptr;
+ return llvm::errorCodeToError(statError);
}
// It exists. See if we have already opened a directory with the
@@ -158,24 +173,51 @@ const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
// Windows).
DirectoryEntry &UDE = UniqueRealDirs[Status.getUniqueID()];
- NamedDirEnt.second = &UDE;
+ NamedDirEnt.second = UDE;
if (UDE.getName().empty()) {
// We don't have this directory yet, add it. We use the string
// key from the SeenDirEntries map as the string.
UDE.Name = InterndDirName;
}
- return &UDE;
+ return DirectoryEntryRef(&NamedDirEnt);
+}
+
+llvm::ErrorOr<const DirectoryEntry *>
+FileManager::getDirectory(StringRef DirName, bool CacheFailure) {
+ auto Result = getDirectoryRef(DirName, CacheFailure);
+ if (Result)
+ return &Result->getDirEntry();
+ return llvm::errorToErrorCode(Result.takeError());
}
-const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
- bool CacheFailure) {
+llvm::ErrorOr<const FileEntry *>
+FileManager::getFile(StringRef Filename, bool openFile, bool CacheFailure) {
+ auto Result = getFileRef(Filename, openFile, CacheFailure);
+ if (Result)
+ return &Result->getFileEntry();
+ return llvm::errorToErrorCode(Result.takeError());
+}
+
+llvm::Expected<FileEntryRef>
+FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
++NumFileLookups;
// See if there is already an entry in the map.
- auto SeenFileInsertResult = SeenFileEntries.insert({Filename, nullptr});
- if (!SeenFileInsertResult.second)
- return SeenFileInsertResult.first->second;
+ auto SeenFileInsertResult =
+ SeenFileEntries.insert({Filename, std::errc::no_such_file_or_directory});
+ if (!SeenFileInsertResult.second) {
+ if (!SeenFileInsertResult.first->second)
+ return llvm::errorCodeToError(
+ SeenFileInsertResult.first->second.getError());
+ // Construct and return and FileEntryRef, unless it's a redirect to another
+ // filename.
+ SeenFileEntryOrRedirect Value = *SeenFileInsertResult.first->second;
+ FileEntry *FE;
+ if (LLVM_LIKELY(FE = Value.dyn_cast<FileEntry *>()))
+ return FileEntryRef(SeenFileInsertResult.first->first(), *FE);
+ return getFileRef(*Value.get<const StringRef *>(), openFile, CacheFailure);
+ }
// We've not seen this before. Fill it in.
++NumFileCacheMisses;
@@ -191,14 +233,16 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
// subdirectory. This will let us avoid having to waste time on known-to-fail
// searches when we go to find sys/bar.h, because all the search directories
// without a 'sys' subdir will get a cached failure result.
- const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename,
- CacheFailure);
- if (DirInfo == nullptr) { // Directory doesn't exist, file can't exist.
- if (!CacheFailure)
+ auto DirInfoOrErr = getDirectoryFromFile(*this, Filename, CacheFailure);
+ if (!DirInfoOrErr) { // Directory doesn't exist, file can't exist.
+ if (CacheFailure)
+ NamedFileEnt.second = DirInfoOrErr.getError();
+ else
SeenFileEntries.erase(Filename);
- return nullptr;
+ return llvm::errorCodeToError(DirInfoOrErr.getError());
}
+ const DirectoryEntry *DirInfo = *DirInfoOrErr;
// FIXME: Use the directory info to prune this, before doing the stat syscall.
// FIXME: This will reduce the # syscalls.
@@ -206,12 +250,16 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
// Check to see if the file exists.
std::unique_ptr<llvm::vfs::File> F;
llvm::vfs::Status Status;
- if (getStatValue(InterndFileName, Status, true, openFile ? &F : nullptr)) {
+ auto statError = getStatValue(InterndFileName, Status, true,
+ openFile ? &F : nullptr);
+ if (statError) {
// There's no real file at the given path.
- if (!CacheFailure)
+ if (CacheFailure)
+ NamedFileEnt.second = statError;
+ else
SeenFileEntries.erase(Filename);
- return nullptr;
+ return llvm::errorCodeToError(statError);
}
assert((openFile || !F) && "undesired open file");
@@ -225,11 +273,15 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
// If the name returned by getStatValue is different than Filename, re-intern
// the name.
if (Status.getName() != Filename) {
- auto &NamedFileEnt =
- *SeenFileEntries.insert({Status.getName(), &UFE}).first;
- assert(NamedFileEnt.second == &UFE &&
+ auto &NewNamedFileEnt =
+ *SeenFileEntries.insert({Status.getName(), &UFE}).first;
+ assert((*NewNamedFileEnt.second).get<FileEntry *>() == &UFE &&
"filename from getStatValue() refers to wrong file");
- InterndFileName = NamedFileEnt.first().data();
+ InterndFileName = NewNamedFileEnt.first().data();
+ // In addition to re-interning the name, construct a redirecting seen file
+ // entry, that will point to the name the filesystem actually wants to use.
+ StringRef *Redirect = new (CanonicalNameStorage) StringRef(InterndFileName);
+ NamedFileEnt.second = Redirect;
}
if (UFE.isValid()) { // Already have an entry with this inode, return it.
@@ -248,9 +300,11 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
// to switch towards a design where we return a FileName object that
// encapsulates both the name by which the file was accessed and the
// corresponding FileEntry.
+ // FIXME: The Name should be removed from FileEntry once all clients
+ // adopt FileEntryRef.
UFE.Name = InterndFileName;
- return &UFE;
+ return FileEntryRef(InterndFileName, UFE);
}
// Otherwise, we don't have this file yet, add it.
@@ -271,7 +325,7 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
// We should still fill the path even if we aren't opening the file.
fillRealPathName(&UFE, InterndFileName);
}
- return &UFE;
+ return FileEntryRef(InterndFileName, UFE);
}
const FileEntry *
@@ -280,9 +334,16 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
++NumFileLookups;
// See if there is already an entry in the map for an existing file.
- auto &NamedFileEnt = *SeenFileEntries.insert({Filename, nullptr}).first;
- if (NamedFileEnt.second)
- return NamedFileEnt.second;
+ auto &NamedFileEnt = *SeenFileEntries.insert(
+ {Filename, std::errc::no_such_file_or_directory}).first;
+ if (NamedFileEnt.second) {
+ SeenFileEntryOrRedirect Value = *NamedFileEnt.second;
+ FileEntry *FE;
+ if (LLVM_LIKELY(FE = Value.dyn_cast<FileEntry *>()))
+ return FE;
+ return getVirtualFile(*Value.get<const StringRef *>(), Size,
+ ModificationTime);
+ }
// We've not seen this before, or the file is cached as non-existent.
++NumFileCacheMisses;
@@ -292,15 +353,14 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
// Now that all ancestors of Filename are in the cache, the
// following call is guaranteed to find the DirectoryEntry from the
// cache.
- const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename,
- /*CacheFailure=*/true);
+ auto DirInfo = getDirectoryFromFile(*this, Filename, /*CacheFailure=*/true);
assert(DirInfo &&
"The directory of a virtual file should already be in the cache.");
// Check to see if the file exists. If so, drop the virtual file
llvm::vfs::Status Status;
const char *InterndFileName = NamedFileEnt.first().data();
- if (getStatValue(InterndFileName, Status, true, nullptr) == 0) {
+ if (!getStatValue(InterndFileName, Status, true, nullptr)) {
UFE = &UniqueRealFiles[Status.getUniqueID()];
Status = llvm::vfs::Status(
Status.getName(), Status.getUniqueID(),
@@ -324,7 +384,7 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
UFE->IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file;
fillRealPathName(UFE, Status.getName());
} else {
- VirtualFileEntries.push_back(llvm::make_unique<FileEntry>());
+ VirtualFileEntries.push_back(std::make_unique<FileEntry>());
UFE = VirtualFileEntries.back().get();
NamedFileEnt.second = UFE;
}
@@ -332,13 +392,32 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
UFE->Name = InterndFileName;
UFE->Size = Size;
UFE->ModTime = ModificationTime;
- UFE->Dir = DirInfo;
+ UFE->Dir = *DirInfo;
UFE->UID = NextFileUID++;
UFE->IsValid = true;
UFE->File.reset();
return UFE;
}
+llvm::Optional<FileEntryRef> FileManager::getBypassFile(FileEntryRef VF) {
+ // Stat of the file and return nullptr if it doesn't exist.
+ llvm::vfs::Status Status;
+ if (getStatValue(VF.getName(), Status, /*isFile=*/true, /*F=*/nullptr))
+ return None;
+
+ // Fill it in from the stat.
+ BypassFileEntries.push_back(std::make_unique<FileEntry>());
+ const FileEntry &VFE = VF.getFileEntry();
+ FileEntry &BFE = *BypassFileEntries.back();
+ BFE.Name = VFE.getName();
+ BFE.Size = Status.getSize();
+ BFE.Dir = VFE.Dir;
+ BFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime());
+ BFE.UID = NextFileUID++;
+ BFE.IsValid = true;
+ return FileEntryRef(VF.getName(), BFE);
+}
+
bool FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const {
StringRef pathRef(path.data(), path.size());
@@ -375,8 +454,7 @@ void FileManager::fillRealPathName(FileEntry *UFE, llvm::StringRef FileName) {
}
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
-FileManager::getBufferForFile(const FileEntry *Entry, bool isVolatile,
- bool ShouldCloseOpenFile) {
+FileManager::getBufferForFile(const FileEntry *Entry, bool isVolatile) {
uint64_t FileSize = Entry->getSize();
// If there's a high enough chance that the file have changed since we
// got its size, force a stat before opening it.
@@ -389,80 +467,59 @@ FileManager::getBufferForFile(const FileEntry *Entry, bool isVolatile,
auto Result =
Entry->File->getBuffer(Filename, FileSize,
/*RequiresNullTerminator=*/true, isVolatile);
- // FIXME: we need a set of APIs that can make guarantees about whether a
- // FileEntry is open or not.
- if (ShouldCloseOpenFile)
- Entry->closeFile();
+ Entry->closeFile();
return Result;
}
// Otherwise, open the file.
+ return getBufferForFileImpl(Filename, FileSize, isVolatile);
+}
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+FileManager::getBufferForFileImpl(StringRef Filename, int64_t FileSize,
+ bool isVolatile) {
if (FileSystemOpts.WorkingDir.empty())
return FS->getBufferForFile(Filename, FileSize,
/*RequiresNullTerminator=*/true, isVolatile);
- SmallString<128> FilePath(Entry->getName());
+ SmallString<128> FilePath(Filename);
FixupRelativePath(FilePath);
return FS->getBufferForFile(FilePath, FileSize,
/*RequiresNullTerminator=*/true, isVolatile);
}
-llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
-FileManager::getBufferForFile(StringRef Filename, bool isVolatile) {
- if (FileSystemOpts.WorkingDir.empty())
- return FS->getBufferForFile(Filename, -1, true, isVolatile);
-
- SmallString<128> FilePath(Filename);
- FixupRelativePath(FilePath);
- return FS->getBufferForFile(FilePath.c_str(), -1, true, isVolatile);
-}
-
/// getStatValue - Get the 'stat' information for the specified path,
/// using the cache to accelerate it if possible. This returns true
/// if the path points to a virtual file or does not exist, or returns
/// false if it's an existent real file. If FileDescriptor is NULL,
/// do directory look-up instead of file look-up.
-bool FileManager::getStatValue(StringRef Path, llvm::vfs::Status &Status,
- bool isFile,
- std::unique_ptr<llvm::vfs::File> *F) {
+std::error_code
+FileManager::getStatValue(StringRef Path, llvm::vfs::Status &Status,
+ bool isFile, std::unique_ptr<llvm::vfs::File> *F) {
// FIXME: FileSystemOpts shouldn't be passed in here, all paths should be
// absolute!
if (FileSystemOpts.WorkingDir.empty())
- return bool(FileSystemStatCache::get(Path, Status, isFile, F,
- StatCache.get(), *FS));
+ return FileSystemStatCache::get(Path, Status, isFile, F,
+ StatCache.get(), *FS);
SmallString<128> FilePath(Path);
FixupRelativePath(FilePath);
- return bool(FileSystemStatCache::get(FilePath.c_str(), Status, isFile, F,
- StatCache.get(), *FS));
+ return FileSystemStatCache::get(FilePath.c_str(), Status, isFile, F,
+ StatCache.get(), *FS);
}
-bool FileManager::getNoncachedStatValue(StringRef Path,
- llvm::vfs::Status &Result) {
+std::error_code
+FileManager::getNoncachedStatValue(StringRef Path,
+ llvm::vfs::Status &Result) {
SmallString<128> FilePath(Path);
FixupRelativePath(FilePath);
llvm::ErrorOr<llvm::vfs::Status> S = FS->status(FilePath.c_str());
if (!S)
- return true;
+ return S.getError();
Result = *S;
- return false;
-}
-
-void FileManager::invalidateCache(const FileEntry *Entry) {
- assert(Entry && "Cannot invalidate a NULL FileEntry");
-
- SeenFileEntries.erase(Entry->getName());
-
- // FileEntry invalidation should not block future optimizations in the file
- // caches. Possible alternatives are cache truncation (invalidate last N) or
- // invalidation of the whole cache.
- //
- // FIXME: This is broken. We sometimes have the same FileEntry* shared
- // betweeen multiple SeenFileEntries, so this can leave dangling pointers.
- UniqueRealFiles.erase(Entry->getUniqueID());
+ return std::error_code();
}
void FileManager::GetUniqueIDMapping(
@@ -471,23 +528,21 @@ void FileManager::GetUniqueIDMapping(
UIDToFiles.resize(NextFileUID);
// Map file entries
- for (llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator>::const_iterator
- FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end();
+ for (llvm::StringMap<llvm::ErrorOr<SeenFileEntryOrRedirect>,
+ llvm::BumpPtrAllocator>::const_iterator
+ FE = SeenFileEntries.begin(),
+ FEEnd = SeenFileEntries.end();
FE != FEEnd; ++FE)
- if (FE->getValue())
- UIDToFiles[FE->getValue()->getUID()] = FE->getValue();
+ if (llvm::ErrorOr<SeenFileEntryOrRedirect> Entry = FE->getValue()) {
+ if (const auto *FE = (*Entry).dyn_cast<FileEntry *>())
+ UIDToFiles[FE->getUID()] = FE;
+ }
// Map virtual file entries
for (const auto &VFE : VirtualFileEntries)
UIDToFiles[VFE->getUID()] = VFE.get();
}
-void FileManager::modifyFileEntry(FileEntry *File,
- off_t Size, time_t ModificationTime) {
- File->Size = Size;
- File->ModTime = ModificationTime;
-}
-
StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) {
// FIXME: use llvm::sys::fs::canonical() when it gets implemented
llvm::DenseMap<const DirectoryEntry *, llvm::StringRef>::iterator Known
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index ca9c71287ab7..4aebea19924f 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -412,6 +412,21 @@ public:
} // namespace clang.
+bool Selector::isKeywordSelector(ArrayRef<StringRef> Names) const {
+ assert(!Names.empty() && "must have >= 1 selector slots");
+ if (getNumArgs() != Names.size())
+ return false;
+ for (unsigned I = 0, E = Names.size(); I != E; ++I) {
+ if (getNameForSlot(I) != Names[I])
+ return false;
+ }
+ return true;
+}
+
+bool Selector::isUnarySelector(StringRef Name) const {
+ return isUnarySelector() && getNameForSlot(0) == Name;
+}
+
unsigned Selector::getNumArgs() const {
unsigned IIF = getIdentifierInfoFlag();
if (IIF <= ZeroArg)
diff --git a/lib/Frontend/LangStandards.cpp b/lib/Basic/LangStandards.cpp
index 05087eb41f01..ee27bfd12113 100644
--- a/lib/Frontend/LangStandards.cpp
+++ b/lib/Basic/LangStandards.cpp
@@ -6,15 +6,14 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/LangStandard.h"
+#include "clang/Basic/LangStandard.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
-using namespace clang::frontend;
-#define LANGSTANDARD(id, name, lang, desc, features) \
-static const LangStandard Lang_##id = { name, desc, features, InputKind::lang };
-#include "clang/Frontend/LangStandards.def"
+#define LANGSTANDARD(id, name, lang, desc, features) \
+ static const LangStandard Lang_##id = {name, desc, features, Language::lang};
+#include "clang/Basic/LangStandards.def"
const LangStandard &LangStandard::getLangStandardForKind(Kind K) {
switch (K) {
@@ -22,17 +21,21 @@ const LangStandard &LangStandard::getLangStandardForKind(Kind K) {
llvm::report_fatal_error("getLangStandardForKind() on unspecified kind");
#define LANGSTANDARD(id, name, lang, desc, features) \
case lang_##id: return Lang_##id;
-#include "clang/Frontend/LangStandards.def"
+#include "clang/Basic/LangStandards.def"
}
llvm_unreachable("Invalid language kind!");
}
+LangStandard::Kind LangStandard::getLangKind(StringRef Name) {
+ return llvm::StringSwitch<Kind>(Name)
+#define LANGSTANDARD(id, name, lang, desc, features) .Case(name, lang_##id)
+#define LANGSTANDARD_ALIAS(id, alias) .Case(alias, lang_##id)
+#include "clang/Basic/LangStandards.def"
+ .Default(lang_unspecified);
+}
+
const LangStandard *LangStandard::getLangStandardForName(StringRef Name) {
- Kind K = llvm::StringSwitch<Kind>(Name)
-#define LANGSTANDARD(id, name, lang, desc, features) \
- .Case(name, lang_##id)
-#include "clang/Frontend/LangStandards.def"
- .Default(lang_unspecified);
+ Kind K = getLangKind(Name);
if (K == lang_unspecified)
return nullptr;
diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
index f394f26e550c..541431dbbe7d 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -246,8 +246,8 @@ ArrayRef<const FileEntry *> Module::getTopHeaders(FileManager &FileMgr) {
if (!TopHeaderNames.empty()) {
for (std::vector<std::string>::iterator
I = TopHeaderNames.begin(), E = TopHeaderNames.end(); I != E; ++I) {
- if (const FileEntry *FE = FileMgr.getFile(*I))
- TopHeaders.insert(FE);
+ if (auto FE = FileMgr.getFile(*I))
+ TopHeaders.insert(*FE);
}
TopHeaderNames.clear();
}
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index 82e193efef32..a52ed8caa121 100644
--- a/lib/Basic/OpenMPKinds.cpp
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -55,6 +55,8 @@ OpenMPClauseKind clang::getOpenMPClauseKind(StringRef Str) {
#define OPENMP_CLAUSE(Name, Class) .Case(#Name, OMPC_##Name)
#include "clang/Basic/OpenMPKinds.def"
.Case("uniform", OMPC_uniform)
+ .Case("device_type", OMPC_device_type)
+ .Case("match", OMPC_match)
.Default(OMPC_unknown);
}
@@ -71,6 +73,10 @@ const char *clang::getOpenMPClauseName(OpenMPClauseKind Kind) {
return "uniform";
case OMPC_threadprivate:
return "threadprivate or thread local";
+ case OMPC_device_type:
+ return "device_type";
+ case OMPC_match:
+ return "match";
}
llvm_unreachable("Invalid OpenMP clause kind");
}
@@ -145,6 +151,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
.Case(#Name, OMPC_ATOMIC_DEFAULT_MEM_ORDER_##Name)
#include "clang/Basic/OpenMPKinds.def"
.Default(OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown);
+ case OMPC_device_type:
+ return llvm::StringSwitch<OpenMPDeviceType>(Str)
+#define OPENMP_DEVICE_TYPE_KIND(Name) .Case(#Name, OMPC_DEVICE_TYPE_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMPC_DEVICE_TYPE_unknown);
case OMPC_unknown:
case OMPC_threadprivate:
case OMPC_if:
@@ -192,6 +203,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
case OMPC_unified_shared_memory:
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
+ case OMPC_match:
break;
}
llvm_unreachable("Invalid OpenMP simple clause kind");
@@ -328,6 +340,16 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
#include "clang/Basic/OpenMPKinds.def"
}
llvm_unreachable("Invalid OpenMP 'atomic_default_mem_order' clause type");
+ case OMPC_device_type:
+ switch (Type) {
+ case OMPC_DEVICE_TYPE_unknown:
+ return "unknown";
+#define OPENMP_DEVICE_TYPE_KIND(Name) \
+ case OMPC_DEVICE_TYPE_##Name: \
+ return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ }
+ llvm_unreachable("Invalid OpenMP 'device_type' clause type");
case OMPC_unknown:
case OMPC_threadprivate:
case OMPC_if:
@@ -375,6 +397,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_unified_shared_memory:
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
+ case OMPC_match:
break;
}
llvm_unreachable("Invalid OpenMP simple clause kind");
@@ -588,8 +611,6 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
break;
}
break;
- case OMPD_declare_simd:
- break;
case OMPD_cancel:
switch (CKind) {
#define OPENMP_CANCEL_CLAUSE(Name) \
@@ -630,6 +651,36 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
break;
}
break;
+ case OMPD_master_taskloop:
+ switch (CKind) {
+#define OPENMP_MASTER_TASKLOOP_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_master_taskloop_simd:
+ switch (CKind) {
+#define OPENMP_MASTER_TASKLOOP_SIMD_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
+ case OMPD_parallel_master_taskloop:
+ switch (CKind) {
+#define OPENMP_PARALLEL_MASTER_TASKLOOP_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
case OMPD_critical:
switch (CKind) {
#define OPENMP_CRITICAL_CLAUSE(Name) \
@@ -820,6 +871,16 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
break;
}
break;
+ case OMPD_declare_variant:
+ switch (CKind) {
+#define OPENMP_DECLARE_VARIANT_CLAUSE(Name) \
+ case OMPC_##Name: \
+ return true;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ break;
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_unknown:
@@ -831,6 +892,7 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_declare_reduction:
+ case OMPD_declare_simd:
break;
}
return false;
@@ -840,7 +902,9 @@ bool clang::isOpenMPLoopDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_simd || DKind == OMPD_for || DKind == OMPD_for_simd ||
DKind == OMPD_parallel_for || DKind == OMPD_parallel_for_simd ||
DKind == OMPD_taskloop || DKind == OMPD_taskloop_simd ||
- DKind == OMPD_distribute || DKind == OMPD_target_parallel_for ||
+ DKind == OMPD_master_taskloop || DKind == OMPD_master_taskloop_simd ||
+ DKind == OMPD_parallel_master_taskloop || DKind == OMPD_distribute ||
+ DKind == OMPD_target_parallel_for ||
DKind == OMPD_distribute_parallel_for ||
DKind == OMPD_distribute_parallel_for_simd ||
DKind == OMPD_distribute_simd ||
@@ -871,7 +935,9 @@ bool clang::isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind) {
}
bool clang::isOpenMPTaskLoopDirective(OpenMPDirectiveKind DKind) {
- return DKind == OMPD_taskloop || DKind == OMPD_taskloop_simd;
+ return DKind == OMPD_taskloop || DKind == OMPD_taskloop_simd ||
+ DKind == OMPD_master_taskloop || DKind == OMPD_master_taskloop_simd ||
+ DKind == OMPD_parallel_master_taskloop;
}
bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) {
@@ -884,7 +950,8 @@ bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) {
DKind == OMPD_teams_distribute_parallel_for ||
DKind == OMPD_teams_distribute_parallel_for_simd ||
DKind == OMPD_target_teams_distribute_parallel_for ||
- DKind == OMPD_target_teams_distribute_parallel_for_simd;
+ DKind == OMPD_target_teams_distribute_parallel_for_simd ||
+ DKind == OMPD_parallel_master_taskloop;
}
bool clang::isOpenMPTargetExecutionDirective(OpenMPDirectiveKind DKind) {
@@ -920,6 +987,7 @@ bool clang::isOpenMPTeamsDirective(OpenMPDirectiveKind DKind) {
bool clang::isOpenMPSimdDirective(OpenMPDirectiveKind DKind) {
return DKind == OMPD_simd || DKind == OMPD_for_simd ||
DKind == OMPD_parallel_for_simd || DKind == OMPD_taskloop_simd ||
+ DKind == OMPD_master_taskloop_simd ||
DKind == OMPD_distribute_parallel_for_simd ||
DKind == OMPD_distribute_simd || DKind == OMPD_target_simd ||
DKind == OMPD_teams_distribute_simd ||
@@ -1021,6 +1089,12 @@ void clang::getOpenMPCaptureRegions(
break;
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ CaptureRegions.push_back(OMPD_taskloop);
+ break;
+ case OMPD_parallel_master_taskloop:
+ CaptureRegions.push_back(OMPD_parallel);
CaptureRegions.push_back(OMPD_taskloop);
break;
case OMPD_target_teams_distribute_parallel_for:
@@ -1060,6 +1134,7 @@ void clang::getOpenMPCaptureRegions(
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_requires:
+ case OMPD_declare_variant:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 12b0305e707c..58b95289eaf2 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -96,7 +96,7 @@ void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B, bool DoNotFree) {
}
const llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
- const SourceManager &SM,
+ FileManager &FM,
SourceLocation Loc,
bool *Invalid) const {
// Lazily create the Buffer for ContentCaches that wrap files. If we already
@@ -134,9 +134,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag,
return Buffer.getPointer();
}
- bool isVolatile = SM.userFilesAreVolatile() && !IsSystemFile;
- auto BufferOrError =
- SM.getFileManager().getBufferForFile(ContentsEntry, isVolatile);
+ auto BufferOrError = FM.getBufferForFile(ContentsEntry, IsFileVolatile);
// If we were unable to open the file, then we are in an inconsistent
// situation where the content cache referenced a file which no longer
@@ -389,7 +387,7 @@ void SourceManager::initializeForReplay(const SourceManager &Old) {
Clone->OrigEntry = Cache->OrigEntry;
Clone->ContentsEntry = Cache->ContentsEntry;
Clone->BufferOverridden = Cache->BufferOverridden;
- Clone->IsSystemFile = Cache->IsSystemFile;
+ Clone->IsFileVolatile = Cache->IsFileVolatile;
Clone->IsTransient = Cache->IsTransient;
Clone->replaceBuffer(Cache->getRawBuffer(), /*DoNotFree*/true);
return Clone;
@@ -438,7 +436,7 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt,
new (Entry) ContentCache(FileEnt);
}
- Entry->IsSystemFile = isSystemFile;
+ Entry->IsFileVolatile = UserFilesAreVolatile && !isSystemFile;
Entry->IsTransient = FilesAreTransient;
return Entry;
@@ -466,10 +464,9 @@ const SrcMgr::SLocEntry &SourceManager::loadSLocEntry(unsigned Index,
// 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));
+ LoadedSLocEntryTable[Index] = SLocEntry::get(
+ 0, FileInfo::get(SourceLocation(), getFakeContentCacheForRecovery(),
+ SrcMgr::C_User, ""));
}
}
@@ -505,7 +502,7 @@ llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const {
const SrcMgr::ContentCache *
SourceManager::getFakeContentCacheForRecovery() const {
if (!FakeContentCacheForRecovery) {
- FakeContentCacheForRecovery = llvm::make_unique<SrcMgr::ContentCache>();
+ FakeContentCacheForRecovery = std::make_unique<SrcMgr::ContentCache>();
FakeContentCacheForRecovery->replaceBuffer(getFakeBufferForRecovery(),
/*DoNotFree=*/true);
}
@@ -556,7 +553,7 @@ FileID SourceManager::getNextFileID(FileID FID) const {
/// createFileID - Create a new FileID for the specified ContentCache and
/// include position. This works regardless of whether the ContentCache
/// corresponds to a file or some other input source.
-FileID SourceManager::createFileID(const ContentCache *File,
+FileID SourceManager::createFileID(const ContentCache *File, StringRef Filename,
SourceLocation IncludePos,
SrcMgr::CharacteristicKind FileCharacter,
int LoadedID, unsigned LoadedOffset) {
@@ -565,14 +562,14 @@ FileID SourceManager::createFileID(const ContentCache *File,
unsigned Index = unsigned(-LoadedID) - 2;
assert(Index < LoadedSLocEntryTable.size() && "FileID out of range");
assert(!SLocEntryLoaded[Index] && "FileID already loaded");
- LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset,
- FileInfo::get(IncludePos, File, FileCharacter));
+ LoadedSLocEntryTable[Index] = SLocEntry::get(
+ LoadedOffset, FileInfo::get(IncludePos, File, FileCharacter, Filename));
SLocEntryLoaded[Index] = true;
return FileID::get(LoadedID);
}
- LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset,
- FileInfo::get(IncludePos, File,
- FileCharacter)));
+ LocalSLocEntryTable.push_back(
+ SLocEntry::get(NextLocalOffset,
+ FileInfo::get(IncludePos, File, FileCharacter, Filename)));
unsigned FileSize = File->getSize();
assert(NextLocalOffset + FileSize + 1 > NextLocalOffset &&
NextLocalOffset + FileSize + 1 <= CurrentLoadedOffset &&
@@ -646,7 +643,7 @@ const llvm::MemoryBuffer *
SourceManager::getMemoryBufferForFile(const FileEntry *File, bool *Invalid) {
const SrcMgr::ContentCache *IR = getOrCreateContentCache(File);
assert(IR && "getOrCreateContentCache() cannot return NULL");
- return IR->getBuffer(Diag, *this, SourceLocation(), Invalid);
+ return IR->getBuffer(Diag, getFileManager(), SourceLocation(), Invalid);
}
void SourceManager::overrideFileContents(const FileEntry *SourceFile,
@@ -672,17 +669,19 @@ void SourceManager::overrideFileContents(const FileEntry *SourceFile,
getOverriddenFilesInfo().OverriddenFiles[SourceFile] = NewFile;
}
-void SourceManager::disableFileContentsOverride(const FileEntry *File) {
- if (!isFileOverridden(File))
- return;
+const FileEntry *
+SourceManager::bypassFileContentsOverride(const FileEntry &File) {
+ assert(isFileOverridden(&File));
+ llvm::Optional<FileEntryRef> BypassFile =
+ FileMgr.getBypassFile(FileEntryRef(File.getName(), File));
- const SrcMgr::ContentCache *IR = getOrCreateContentCache(File);
- const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(nullptr);
- const_cast<SrcMgr::ContentCache *>(IR)->ContentsEntry = IR->OrigEntry;
+ // If the file can't be found in the FS, give up.
+ if (!BypassFile)
+ return nullptr;
- assert(OverriddenFilesInfo);
- OverriddenFilesInfo->OverriddenFiles.erase(File);
- OverriddenFilesInfo->OverriddenFilesWithBuffer.erase(File);
+ const FileEntry *FE = &BypassFile->getFileEntry();
+ (void)getOrCreateContentCache(FE);
+ return FE;
}
void SourceManager::setFileIsTransient(const FileEntry *File) {
@@ -700,7 +699,7 @@ StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const {
}
const llvm::MemoryBuffer *Buf = SLoc.getFile().getContentCache()->getBuffer(
- Diag, *this, SourceLocation(), &MyInvalid);
+ Diag, getFileManager(), SourceLocation(), &MyInvalid);
if (Invalid)
*Invalid = MyInvalid;
@@ -1131,7 +1130,7 @@ const char *SourceManager::getCharacterData(SourceLocation SL,
}
const llvm::MemoryBuffer *Buffer =
Entry.getFile().getContentCache()->getBuffer(
- Diag, *this, SourceLocation(), &CharDataInvalid);
+ Diag, getFileManager(), SourceLocation(), &CharDataInvalid);
if (Invalid)
*Invalid = CharDataInvalid;
return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second);
@@ -1228,7 +1227,7 @@ static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI,
const SourceManager &SM, bool &Invalid) {
// Note that calling 'getBuffer()' may lazily page in the file.
const MemoryBuffer *Buffer =
- FI->getBuffer(Diag, SM, SourceLocation(), &Invalid);
+ FI->getBuffer(Diag, SM.getFileManager(), SourceLocation(), &Invalid);
if (Invalid)
return;
@@ -1459,7 +1458,7 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc,
if (C->OrigEntry)
Filename = C->OrigEntry->getName();
else
- Filename = C->getBuffer(Diag, *this)->getBufferIdentifier();
+ Filename = C->getBuffer(Diag, getFileManager())->getBufferIdentifier();
unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second, &Invalid);
if (Invalid)
@@ -1558,22 +1557,6 @@ unsigned SourceManager::getFileIDSize(FileID FID) const {
// Other miscellaneous methods.
//===----------------------------------------------------------------------===//
-/// Retrieve the inode for the given file entry, if possible.
-///
-/// This routine involves a system call, and therefore should only be used
-/// in non-performance-critical code.
-static Optional<llvm::sys::fs::UniqueID>
-getActualFileUID(const FileEntry *File) {
- if (!File)
- return None;
-
- llvm::sys::fs::UniqueID ID;
- if (llvm::sys::fs::getUniqueID(File->getName(), ID))
- return None;
-
- return ID;
-}
-
/// Get the source location for the given file:line:col triplet.
///
/// If the source file is included multiple times, the source location will
@@ -1595,13 +1578,8 @@ SourceLocation SourceManager::translateFileLineCol(const FileEntry *SourceFile,
FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
assert(SourceFile && "Null source file!");
- // Find the first file ID that corresponds to the given file.
- FileID FirstFID;
-
// First, check the main file ID, since it is common to look for a
// location in the main file.
- Optional<llvm::sys::fs::UniqueID> SourceFileUID;
- Optional<StringRef> SourceFileName;
if (MainFileID.isValid()) {
bool Invalid = false;
const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid);
@@ -1609,100 +1587,35 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
return FileID();
if (MainSLoc.isFile()) {
- const ContentCache *MainContentCache
- = MainSLoc.getFile().getContentCache();
- if (!MainContentCache || !MainContentCache->OrigEntry) {
- // Can't do anything
- } else if (MainContentCache->OrigEntry == SourceFile) {
- FirstFID = MainFileID;
- } else {
- // Fall back: check whether we have the same base name and inode
- // as the main file.
- const FileEntry *MainFile = MainContentCache->OrigEntry;
- SourceFileName = llvm::sys::path::filename(SourceFile->getName());
- if (*SourceFileName == llvm::sys::path::filename(MainFile->getName())) {
- SourceFileUID = getActualFileUID(SourceFile);
- if (SourceFileUID) {
- if (Optional<llvm::sys::fs::UniqueID> MainFileUID =
- getActualFileUID(MainFile)) {
- if (*SourceFileUID == *MainFileUID) {
- FirstFID = MainFileID;
- SourceFile = MainFile;
- }
- }
- }
- }
- }
+ const ContentCache *MainContentCache =
+ MainSLoc.getFile().getContentCache();
+ if (MainContentCache && MainContentCache->OrigEntry == SourceFile)
+ return MainFileID;
}
}
- if (FirstFID.isInvalid()) {
- // The location we're looking for isn't in the main file; look
- // through all of the local source locations.
- for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) {
- bool Invalid = false;
- const SLocEntry &SLoc = getLocalSLocEntry(I, &Invalid);
- if (Invalid)
- return FileID();
+ // The location we're looking for isn't in the main file; look
+ // through all of the local source locations.
+ for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) {
+ bool Invalid = false;
+ const SLocEntry &SLoc = getLocalSLocEntry(I, &Invalid);
+ if (Invalid)
+ return FileID();
- if (SLoc.isFile() &&
- SLoc.getFile().getContentCache() &&
- SLoc.getFile().getContentCache()->OrigEntry == SourceFile) {
- FirstFID = FileID::get(I);
- break;
- }
- }
- // If that still didn't help, try the modules.
- if (FirstFID.isInvalid()) {
- for (unsigned I = 0, N = loaded_sloc_entry_size(); I != N; ++I) {
- const SLocEntry &SLoc = getLoadedSLocEntry(I);
- if (SLoc.isFile() &&
- SLoc.getFile().getContentCache() &&
- SLoc.getFile().getContentCache()->OrigEntry == SourceFile) {
- FirstFID = FileID::get(-int(I) - 2);
- break;
- }
- }
- }
+ if (SLoc.isFile() && SLoc.getFile().getContentCache() &&
+ SLoc.getFile().getContentCache()->OrigEntry == SourceFile)
+ return FileID::get(I);
}
- // If we haven't found what we want yet, try again, but this time stat()
- // each of the files in case the files have changed since we originally
- // parsed the file.
- if (FirstFID.isInvalid() &&
- (SourceFileName ||
- (SourceFileName = llvm::sys::path::filename(SourceFile->getName()))) &&
- (SourceFileUID || (SourceFileUID = getActualFileUID(SourceFile)))) {
- bool Invalid = false;
- for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) {
- FileID IFileID;
- IFileID.ID = I;
- const SLocEntry &SLoc = getSLocEntry(IFileID, &Invalid);
- if (Invalid)
- return FileID();
-
- if (SLoc.isFile()) {
- const ContentCache *FileContentCache
- = SLoc.getFile().getContentCache();
- const FileEntry *Entry = FileContentCache ? FileContentCache->OrigEntry
- : nullptr;
- if (Entry &&
- *SourceFileName == llvm::sys::path::filename(Entry->getName())) {
- if (Optional<llvm::sys::fs::UniqueID> EntryUID =
- getActualFileUID(Entry)) {
- if (*SourceFileUID == *EntryUID) {
- FirstFID = FileID::get(I);
- SourceFile = Entry;
- break;
- }
- }
- }
- }
- }
+ // If that still didn't help, try the modules.
+ for (unsigned I = 0, N = loaded_sloc_entry_size(); I != N; ++I) {
+ const SLocEntry &SLoc = getLoadedSLocEntry(I);
+ if (SLoc.isFile() && SLoc.getFile().getContentCache() &&
+ SLoc.getFile().getContentCache()->OrigEntry == SourceFile)
+ return FileID::get(-int(I) - 2);
}
- (void) SourceFile;
- return FirstFID;
+ return FileID();
}
/// Get the source location in \arg FID for the given line:col.
@@ -1745,13 +1658,13 @@ SourceLocation SourceManager::translateLineCol(FileID FID,
}
if (Line > Content->NumLines) {
- unsigned Size = Content->getBuffer(Diag, *this)->getBufferSize();
+ unsigned Size = Content->getBuffer(Diag, getFileManager())->getBufferSize();
if (Size > 0)
--Size;
return FileLoc.getLocWithOffset(Size);
}
- const llvm::MemoryBuffer *Buffer = Content->getBuffer(Diag, *this);
+ const llvm::MemoryBuffer *Buffer = Content->getBuffer(Diag, getFileManager());
unsigned FilePos = Content->SourceLineCache[Line - 1];
const char *Buf = Buffer->getBufferStart() + FilePos;
unsigned BufLength = Buffer->getBufferSize() - FilePos;
@@ -1927,7 +1840,7 @@ SourceManager::getMacroArgExpandedLocation(SourceLocation Loc) const {
std::unique_ptr<MacroArgsMap> &MacroArgsCache = MacroArgsCacheMap[FID];
if (!MacroArgsCache) {
- MacroArgsCache = llvm::make_unique<MacroArgsMap>();
+ MacroArgsCache = std::make_unique<MacroArgsMap>();
computeMacroArgsCache(*MacroArgsCache, FID);
}
@@ -2256,14 +2169,14 @@ SourceManagerForFile::SourceManagerForFile(StringRef FileName,
// This is passed to `SM` as reference, so the pointer has to be referenced
// in `Environment` so that `FileMgr` can out-live this function scope.
FileMgr =
- llvm::make_unique<FileManager>(FileSystemOptions(), InMemoryFileSystem);
+ std::make_unique<FileManager>(FileSystemOptions(), InMemoryFileSystem);
// This is passed to `SM` as reference, so the pointer has to be referenced
// by `Environment` due to the same reason above.
- Diagnostics = llvm::make_unique<DiagnosticsEngine>(
+ Diagnostics = std::make_unique<DiagnosticsEngine>(
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
new DiagnosticOptions);
- SourceMgr = llvm::make_unique<SourceManager>(*Diagnostics, *FileMgr);
- FileID ID = SourceMgr->createFileID(FileMgr->getFile(FileName),
+ SourceMgr = std::make_unique<SourceManager>(*Diagnostics, *FileMgr);
+ FileID ID = SourceMgr->createFileID(*FileMgr->getFile(FileName),
SourceLocation(), clang::SrcMgr::C_User);
assert(ID.isValid());
SourceMgr->setMainFileID(ID);
diff --git a/lib/Basic/Stack.cpp b/lib/Basic/Stack.cpp
new file mode 100644
index 000000000000..5e4750931500
--- /dev/null
+++ b/lib/Basic/Stack.cpp
@@ -0,0 +1,75 @@
+//===--- Stack.cpp - Utilities for dealing with stack space ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Defines utilities for dealing with stack allocation and stack space.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Stack.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+
+#ifdef _MSC_VER
+#include <intrin.h> // for _AddressOfReturnAddress
+#endif
+
+static LLVM_THREAD_LOCAL void *BottomOfStack = nullptr;
+
+static void *getStackPointer() {
+#if __GNUC__ || __has_builtin(__builtin_frame_address)
+ return __builtin_frame_address(0);
+#elif defined(_MSC_VER)
+ return _AddressOfReturnAddress();
+#else
+ char CharOnStack = 0;
+ // The volatile store here is intended to escape the local variable, to
+ // prevent the compiler from optimizing CharOnStack into anything other
+ // than a char on the stack.
+ //
+ // Tested on: MSVC 2015 - 2019, GCC 4.9 - 9, Clang 3.2 - 9, ICC 13 - 19.
+ char *volatile Ptr = &CharOnStack;
+ return Ptr;
+#endif
+}
+
+void clang::noteBottomOfStack() {
+ if (!BottomOfStack)
+ BottomOfStack = getStackPointer();
+}
+
+bool clang::isStackNearlyExhausted() {
+ // We consider 256 KiB to be sufficient for any code that runs between checks
+ // for stack size.
+ constexpr size_t SufficientStack = 256 << 10;
+
+ // If we don't know where the bottom of the stack is, hope for the best.
+ if (!BottomOfStack)
+ return false;
+
+ intptr_t StackDiff = (intptr_t)getStackPointer() - (intptr_t)BottomOfStack;
+ size_t StackUsage = (size_t)std::abs(StackDiff);
+
+ // If the stack pointer has a surprising value, we do not understand this
+ // stack usage scheme. (Perhaps the target allocates new stack regions on
+ // demand for us.) Don't try to guess what's going on.
+ if (StackUsage > DesiredStackSize)
+ return false;
+
+ return StackUsage >= DesiredStackSize - SufficientStack;
+}
+
+void clang::runWithSufficientStackSpaceSlow(llvm::function_ref<void()> Diag,
+ llvm::function_ref<void()> Fn) {
+ llvm::CrashRecoveryContext CRC;
+ CRC.RunSafelyOnThread([&] {
+ noteBottomOfStack();
+ Diag();
+ Fn();
+ }, DesiredStackSize);
+}
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index a9dfe69b90c5..3a21a19e1f19 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -17,6 +17,7 @@
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/DataLayout.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TargetParser.h"
#include <cstdlib>
@@ -111,6 +112,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
HasAlignMac68kSupport = false;
HasBuiltinMSVaList = false;
IsRenderScriptTarget = false;
+ HasAArch64SVETypes = false;
// Default to no types using fpret.
RealTypeUsesObjCFPRet = 0;
@@ -135,6 +137,10 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
// Out of line virtual dtor for TargetInfo.
TargetInfo::~TargetInfo() {}
+void TargetInfo::resetDataLayout(StringRef DL) {
+ DataLayout.reset(new llvm::DataLayout(DL));
+}
+
bool
TargetInfo::checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const {
Diags.Report(diag::err_opt_not_valid_on_target) << "cf-protection=branch";
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index a08e399e7270..63a64ed2931a 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -363,15 +363,26 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple,
return new AMDGPUTargetInfo(Triple, Opts);
case llvm::Triple::riscv32:
- // TODO: add cases for FreeBSD, NetBSD, RTEMS once tested.
- if (os == llvm::Triple::Linux)
+ // TODO: add cases for NetBSD, RTEMS once tested.
+ switch (os) {
+ case llvm::Triple::FreeBSD:
+ return new FreeBSDTargetInfo<RISCV32TargetInfo>(Triple, Opts);
+ case llvm::Triple::Linux:
return new LinuxTargetInfo<RISCV32TargetInfo>(Triple, Opts);
- return new RISCV32TargetInfo(Triple, Opts);
+ default:
+ return new RISCV32TargetInfo(Triple, Opts);
+ }
+
case llvm::Triple::riscv64:
- // TODO: add cases for FreeBSD, NetBSD, RTEMS once tested.
- if (os == llvm::Triple::Linux)
+ // TODO: add cases for NetBSD, RTEMS once tested.
+ switch (os) {
+ case llvm::Triple::FreeBSD:
+ return new FreeBSDTargetInfo<RISCV64TargetInfo>(Triple, Opts);
+ case llvm::Triple::Linux:
return new LinuxTargetInfo<RISCV64TargetInfo>(Triple, Opts);
- return new RISCV64TargetInfo(Triple, Opts);
+ default:
+ return new RISCV64TargetInfo(Triple, Opts);
+ }
case llvm::Triple::sparc:
switch (os) {
diff --git a/lib/Basic/Targets/AArch64.cpp b/lib/Basic/Targets/AArch64.cpp
index 74ac69ab8946..c86cc63e3d84 100644
--- a/lib/Basic/Targets/AArch64.cpp
+++ b/lib/Basic/Targets/AArch64.cpp
@@ -62,6 +62,16 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple,
// Make __builtin_ms_va_list available.
HasBuiltinMSVaList = true;
+ // Make the SVE types available. Note that this deliberately doesn't
+ // depend on SveMode, since in principle it should be possible to turn
+ // SVE on and off within a translation unit. It should also be possible
+ // to compile the global declaration:
+ //
+ // __SVInt8_t *ptr;
+ //
+ // even without SVE.
+ HasAArch64SVETypes = true;
+
// {} in inline assembly are neon specifiers, not assembly variant
// specifiers.
NoAsmVariants = true;
@@ -196,9 +206,6 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__ARM_NEON_FP", "0xE");
}
- if (FPU & SveMode)
- Builder.defineMacro("__ARM_FEATURE_SVE", "1");
-
if (HasCRC)
Builder.defineMacro("__ARM_FEATURE_CRC32", "1");
@@ -219,6 +226,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasMTE)
Builder.defineMacro("__ARM_FEATURE_MEMORY_TAGGING", "1");
+ if (HasTME)
+ Builder.defineMacro("__ARM_FEATURE_TME", "1");
+
if ((FPU & NeonMode) && HasFP16FML)
Builder.defineMacro("__ARM_FEATURE_FP16FML", "1");
@@ -270,6 +280,7 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasDotProd = false;
HasFP16FML = false;
HasMTE = false;
+ HasTME = false;
ArchKind = llvm::AArch64::ArchKind::ARMV8A;
for (const auto &Feature : Features) {
@@ -301,6 +312,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasFP16FML = true;
if (Feature == "+mte")
HasMTE = true;
+ if (Feature == "+tme")
+ HasTME = true;
}
setDataLayout();
@@ -351,10 +364,19 @@ const char *const AArch64TargetInfo::GCCRegNames[] = {
"d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22",
"d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
- // Vector registers
+ // Neon vector registers
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11",
"v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22",
- "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
+ "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
+
+ // SVE vector registers
+ "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", "z8", "z9", "z10",
+ "z11", "z12", "z13", "z14", "z15", "z16", "z17", "z18", "z19", "z20", "z21",
+ "z22", "z23", "z24", "z25", "z26", "z27", "z28", "z29", "z30", "z31",
+
+ // SVE predicate registers
+ "p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8", "p9", "p10",
+ "p11", "p12", "p13", "p14", "p15"
};
ArrayRef<const char *> AArch64TargetInfo::getGCCRegNames() const {
diff --git a/lib/Basic/Targets/AArch64.h b/lib/Basic/Targets/AArch64.h
index 5833c146003b..b6aa07780edd 100644
--- a/lib/Basic/Targets/AArch64.h
+++ b/lib/Basic/Targets/AArch64.h
@@ -35,6 +35,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
bool HasDotProd;
bool HasFP16FML;
bool HasMTE;
+ bool HasTME;
llvm::AArch64::ArchKind ArchKind;
diff --git a/lib/Basic/Targets/AMDGPU.cpp b/lib/Basic/Targets/AMDGPU.cpp
index b5c82e288570..481630c0fa45 100644
--- a/lib/Basic/Targets/AMDGPU.cpp
+++ b/lib/Basic/Targets/AMDGPU.cpp
@@ -17,6 +17,7 @@
#include "clang/Basic/MacroBuilder.h"
#include "clang/Basic/TargetBuiltins.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/IR/DataLayout.h"
using namespace clang;
using namespace clang::targets;
@@ -131,9 +132,6 @@ bool AMDGPUTargetInfo::initFeatureMap(
// XXX - What does the member GPU mean if device name string passed here?
if (isAMDGCN(getTriple())) {
- if (CPU.empty())
- CPU = "gfx600";
-
switch (llvm::AMDGPU::parseArchAMDGCN(CPU)) {
case GK_GFX1012:
case GK_GFX1011:
@@ -145,6 +143,7 @@ bool AMDGPUTargetInfo::initFeatureMap(
case GK_GFX1010:
Features["dl-insts"] = true;
Features["ci-insts"] = true;
+ Features["flat-address-space"] = true;
Features["16-bit-insts"] = true;
Features["dpp"] = true;
Features["gfx8-insts"] = true;
@@ -184,12 +183,13 @@ bool AMDGPUTargetInfo::initFeatureMap(
case GK_GFX701:
case GK_GFX700:
Features["ci-insts"] = true;
+ Features["flat-address-space"] = true;
LLVM_FALLTHROUGH;
case GK_GFX601:
case GK_GFX600:
break;
case GK_NONE:
- return false;
+ break;
default:
llvm_unreachable("Unhandled GPU!");
}
diff --git a/lib/Basic/Targets/ARM.cpp b/lib/Basic/Targets/ARM.cpp
index c6834b9fac15..437a77afdc99 100644
--- a/lib/Basic/Targets/ARM.cpp
+++ b/lib/Basic/Targets/ARM.cpp
@@ -309,8 +309,9 @@ ARMTargetInfo::ARMTargetInfo(const llvm::Triple &Triple,
setAtomic();
// Maximum alignment for ARM NEON data types should be 64-bits (AAPCS)
+ // as well the default alignment
if (IsAAPCS && (Triple.getEnvironment() != llvm::Triple::Android))
- MaxVectorAlign = 64;
+ DefaultAlignForAttributeAligned = MaxVectorAlign = 64;
// Do force alignment of members that follow zero length bitfields. If
// the alignment of the zero-length bitfield is greater than the member
@@ -321,7 +322,7 @@ ARMTargetInfo::ARMTargetInfo(const llvm::Triple &Triple,
if (Triple.getOS() == llvm::Triple::Linux ||
Triple.getOS() == llvm::Triple::UnknownOS)
this->MCountName = Opts.EABIVersion == llvm::EABI::GNU
- ? "\01__gnu_mcount_nc"
+ ? "llvm.arm.gnu.eabi.mcount"
: "\01mcount";
SoftFloatABI = llvm::is_contained(Opts.FeaturesAsWritten, "+soft-float-abi");
@@ -427,11 +428,10 @@ bool ARMTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
for (const auto &Feature : Features) {
if (Feature == "+soft-float") {
SoftFloat = true;
- } else if (Feature == "+vfp2sp" || Feature == "+vfp2d16sp" ||
- Feature == "+vfp2" || Feature == "+vfp2d16") {
+ } else if (Feature == "+vfp2sp" || Feature == "+vfp2") {
FPU |= VFP2FPU;
HW_FP |= HW_FP_SP;
- if (Feature == "+vfp2" || Feature == "+vfp2d16")
+ if (Feature == "+vfp2")
HW_FP |= HW_FP_DP;
} else if (Feature == "+vfp3sp" || Feature == "+vfp3d16sp" ||
Feature == "+vfp3" || Feature == "+vfp3d16") {
@@ -884,19 +884,102 @@ bool ARMTargetInfo::validateAsmConstraint(
switch (*Name) {
default:
break;
- case 'l': // r0-r7
- case 'h': // r8-r15
- case 't': // VFP Floating point register single precision
- case 'w': // VFP Floating point register double precision
+ case 'l': // r0-r7 if thumb, r0-r15 if ARM
Info.setAllowsRegister();
return true;
+ case 'h': // r8-r15, thumb only
+ if (isThumb()) {
+ Info.setAllowsRegister();
+ return true;
+ }
+ break;
+ case 's': // An integer constant, but allowing only relocatable values.
+ return true;
+ case 't': // s0-s31, d0-d31, or q0-q15
+ case 'w': // s0-s15, d0-d7, or q0-q3
+ case 'x': // s0-s31, d0-d15, or q0-q7
+ Info.setAllowsRegister();
+ return true;
+ case 'j': // An immediate integer between 0 and 65535 (valid for MOVW)
+ // only available in ARMv6T2 and above
+ if (CPUAttr.equals("6T2") || ArchVersion >= 7) {
+ Info.setRequiresImmediate(0, 65535);
+ return true;
+ }
+ break;
case 'I':
+ if (isThumb()) {
+ if (!supportsThumb2())
+ Info.setRequiresImmediate(0, 255);
+ else
+ // FIXME: should check if immediate value would be valid for a Thumb2
+ // data-processing instruction
+ Info.setRequiresImmediate();
+ } else
+ // FIXME: should check if immediate value would be valid for an ARM
+ // data-processing instruction
+ Info.setRequiresImmediate();
+ return true;
case 'J':
+ if (isThumb() && !supportsThumb2())
+ Info.setRequiresImmediate(-255, -1);
+ else
+ Info.setRequiresImmediate(-4095, 4095);
+ return true;
case 'K':
+ if (isThumb()) {
+ if (!supportsThumb2())
+ // FIXME: should check if immediate value can be obtained from shifting
+ // a value between 0 and 255 left by any amount
+ Info.setRequiresImmediate();
+ else
+ // FIXME: should check if immediate value would be valid for a Thumb2
+ // data-processing instruction when inverted
+ Info.setRequiresImmediate();
+ } else
+ // FIXME: should check if immediate value would be valid for an ARM
+ // data-processing instruction when inverted
+ Info.setRequiresImmediate();
+ return true;
case 'L':
+ if (isThumb()) {
+ if (!supportsThumb2())
+ Info.setRequiresImmediate(-7, 7);
+ else
+ // FIXME: should check if immediate value would be valid for a Thumb2
+ // data-processing instruction when negated
+ Info.setRequiresImmediate();
+ } else
+ // FIXME: should check if immediate value would be valid for an ARM
+ // data-processing instruction when negated
+ Info.setRequiresImmediate();
+ return true;
case 'M':
- // FIXME
+ if (isThumb() && !supportsThumb2())
+ // FIXME: should check if immediate value is a multiple of 4 between 0 and
+ // 1020
+ Info.setRequiresImmediate();
+ else
+ // FIXME: should check if immediate value is a power of two or a integer
+ // between 0 and 32
+ Info.setRequiresImmediate();
return true;
+ case 'N':
+ // Thumb1 only
+ if (isThumb() && !supportsThumb2()) {
+ Info.setRequiresImmediate(0, 31);
+ return true;
+ }
+ break;
+ case 'O':
+ // Thumb1 only
+ if (isThumb() && !supportsThumb2()) {
+ // FIXME: should check if immediate value is a multiple of 4 between -508
+ // and 508
+ Info.setRequiresImmediate();
+ return true;
+ }
+ break;
case 'Q': // A memory address that is a single base register.
Info.setAllowsMemory();
return true;
diff --git a/lib/Basic/Targets/BPF.cpp b/lib/Basic/Targets/BPF.cpp
index 0cf55a58a951..2fe2450b9a65 100644
--- a/lib/Basic/Targets/BPF.cpp
+++ b/lib/Basic/Targets/BPF.cpp
@@ -13,11 +13,18 @@
#include "BPF.h"
#include "Targets.h"
#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/TargetBuiltins.h"
#include "llvm/ADT/StringRef.h"
using namespace clang;
using namespace clang::targets;
+const Builtin::Info BPFTargetInfo::BuiltinInfo[] = {
+#define BUILTIN(ID, TYPE, ATTRS) \
+ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr},
+#include "clang/Basic/BuiltinsBPF.def"
+};
+
void BPFTargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
Builder.defineMacro("__bpf__");
@@ -34,3 +41,8 @@ bool BPFTargetInfo::isValidCPUName(StringRef Name) const {
void BPFTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const {
Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames));
}
+
+ArrayRef<Builtin::Info> BPFTargetInfo::getTargetBuiltins() const {
+ return llvm::makeArrayRef(BuiltinInfo, clang::BPF::LastTSBuiltin -
+ Builtin::FirstTSBuiltin);
+}
diff --git a/lib/Basic/Targets/BPF.h b/lib/Basic/Targets/BPF.h
index 79abd8828a2c..117f81430bf4 100644
--- a/lib/Basic/Targets/BPF.h
+++ b/lib/Basic/Targets/BPF.h
@@ -22,6 +22,8 @@ namespace clang {
namespace targets {
class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo {
+ static const Builtin::Info BuiltinInfo[];
+
public:
BPFTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
: TargetInfo(Triple) {
@@ -54,7 +56,7 @@ public:
Features[Name] = Enabled;
}
- ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; }
+ ArrayRef<Builtin::Info> getTargetBuiltins() const override;
const char *getClobbers() const override { return ""; }
diff --git a/lib/Basic/Targets/OSTargets.h b/lib/Basic/Targets/OSTargets.h
index 8542311ffa41..cc72a0a39f30 100644
--- a/lib/Basic/Targets/OSTargets.h
+++ b/lib/Basic/Targets/OSTargets.h
@@ -561,6 +561,10 @@ public:
break;
}
}
+ TargetInfo::CallingConvCheckResult
+ checkCallingConvention(CallingConv CC) const override {
+ return (CC == CC_C) ? TargetInfo::CCCR_OK : TargetInfo::CCCR_Error;
+ }
};
// RTEMS Target
@@ -618,8 +622,11 @@ protected:
Builder.defineMacro("_XOPEN_SOURCE", "600");
else
Builder.defineMacro("_XOPEN_SOURCE", "500");
- if (Opts.CPlusPlus)
+ if (Opts.CPlusPlus) {
Builder.defineMacro("__C99FEATURES__");
+ Builder.defineMacro("_FILE_OFFSET_BITS", "64");
+ }
+ // GCC restricts the next two to C++.
Builder.defineMacro("_LARGEFILE_SOURCE");
Builder.defineMacro("_LARGEFILE64_SOURCE");
Builder.defineMacro("__EXTENSIONS__");
@@ -768,9 +775,11 @@ public:
if (Triple.getArch() == llvm::Triple::arm) {
// Handled in ARM's setABI().
} else if (Triple.getArch() == llvm::Triple::x86) {
- this->resetDataLayout("e-m:e-p:32:32-i64:64-n8:16:32-S128");
+ this->resetDataLayout("e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-"
+ "i64:64-n8:16:32-S128");
} else if (Triple.getArch() == llvm::Triple::x86_64) {
- this->resetDataLayout("e-m:e-p:32:32-i64:64-n8:16:32:64-S128");
+ this->resetDataLayout("e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-"
+ "i64:64-n8:16:32:64-S128");
} else if (Triple.getArch() == llvm::Triple::mipsel) {
// Handled on mips' setDataLayout.
} else {
diff --git a/lib/Basic/Targets/PPC.cpp b/lib/Basic/Targets/PPC.cpp
index 2a773d999286..a40991048873 100644
--- a/lib/Basic/Targets/PPC.cpp
+++ b/lib/Basic/Targets/PPC.cpp
@@ -54,6 +54,10 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasFloat128 = true;
} else if (Feature == "+power9-vector") {
HasP9Vector = true;
+ } else if (Feature == "+spe") {
+ HasSPE = true;
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble();
} else if (Feature == "-hard-float") {
FloatABI = SoftFloat;
}
@@ -165,6 +169,10 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__VEC__", "10206");
Builder.defineMacro("__ALTIVEC__");
}
+ if (HasSPE) {
+ Builder.defineMacro("__SPE__");
+ Builder.defineMacro("__NO_FPRS__");
+ }
if (HasVSX)
Builder.defineMacro("__VSX__");
if (HasP8Vector)
@@ -203,7 +211,6 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
// __CMODEL_LARGE__
// _CALL_SYSV
// _CALL_DARWIN
- // __NO_FPRS__
}
// Handle explicit options being passed to the compiler here: if we've
@@ -332,6 +339,7 @@ bool PPCTargetInfo::hasFeature(StringRef Feature) const {
.Case("extdiv", HasExtDiv)
.Case("float128", HasFloat128)
.Case("power9-vector", HasP9Vector)
+ .Case("spe", HasSPE)
.Default(false);
}
diff --git a/lib/Basic/Targets/PPC.h b/lib/Basic/Targets/PPC.h
index 6e5df097921b..6c6421c28e23 100644
--- a/lib/Basic/Targets/PPC.h
+++ b/lib/Basic/Targets/PPC.h
@@ -66,6 +66,7 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
bool HasBPERMD = false;
bool HasExtDiv = false;
bool HasP9Vector = false;
+ bool HasSPE = false;
protected:
std::string ABI;
diff --git a/lib/Basic/Targets/RISCV.cpp b/lib/Basic/Targets/RISCV.cpp
index f800bb0b25da..ab8272c034fd 100644
--- a/lib/Basic/Targets/RISCV.cpp
+++ b/lib/Basic/Targets/RISCV.cpp
@@ -19,23 +19,38 @@ using namespace clang::targets;
ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const {
static const char *const GCCRegNames[] = {
+ // Integer registers
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
"x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
- "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31"};
+ "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
+
+ // Floating point registers
+ "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"};
return llvm::makeArrayRef(GCCRegNames);
}
ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const {
static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
- {{"zero"}, "x0"}, {{"ra"}, "x1"}, {{"sp"}, "x2"}, {{"gp"}, "x3"},
- {{"tp"}, "x4"}, {{"t0"}, "x5"}, {{"t1"}, "x6"}, {{"t2"}, "x7"},
- {{"s0"}, "x8"}, {{"s1"}, "x9"}, {{"a0"}, "x10"}, {{"a1"}, "x11"},
- {{"a2"}, "x12"}, {{"a3"}, "x13"}, {{"a4"}, "x14"}, {{"a5"}, "x15"},
- {{"a6"}, "x16"}, {{"a7"}, "x17"}, {{"s2"}, "x18"}, {{"s3"}, "x19"},
- {{"s4"}, "x20"}, {{"s5"}, "x21"}, {{"s6"}, "x22"}, {{"s7"}, "x23"},
- {{"s8"}, "x24"}, {{"s9"}, "x25"}, {{"s10"}, "x26"}, {{"s11"}, "x27"},
- {{"t3"}, "x28"}, {{"t4"}, "x29"}, {{"t5"}, "x30"}, {{"t6"}, "x31"}};
+ {{"zero"}, "x0"}, {{"ra"}, "x1"}, {{"sp"}, "x2"}, {{"gp"}, "x3"},
+ {{"tp"}, "x4"}, {{"t0"}, "x5"}, {{"t1"}, "x6"}, {{"t2"}, "x7"},
+ {{"s0"}, "x8"}, {{"s1"}, "x9"}, {{"a0"}, "x10"}, {{"a1"}, "x11"},
+ {{"a2"}, "x12"}, {{"a3"}, "x13"}, {{"a4"}, "x14"}, {{"a5"}, "x15"},
+ {{"a6"}, "x16"}, {{"a7"}, "x17"}, {{"s2"}, "x18"}, {{"s3"}, "x19"},
+ {{"s4"}, "x20"}, {{"s5"}, "x21"}, {{"s6"}, "x22"}, {{"s7"}, "x23"},
+ {{"s8"}, "x24"}, {{"s9"}, "x25"}, {{"s10"}, "x26"}, {{"s11"}, "x27"},
+ {{"t3"}, "x28"}, {{"t4"}, "x29"}, {{"t5"}, "x30"}, {{"t6"}, "x31"},
+ {{"ft0"}, "f0"}, {{"ft1"}, "f1"}, {{"ft2"}, "f2"}, {{"ft3"}, "f3"},
+ {{"ft4"}, "f4"}, {{"ft5"}, "f5"}, {{"ft6"}, "f6"}, {{"ft7"}, "f7"},
+ {{"fs0"}, "f8"}, {{"fs1"}, "f9"}, {{"fa0"}, "f10"}, {{"fa1"}, "f11"},
+ {{"fa2"}, "f12"}, {{"fa3"}, "f13"}, {{"fa4"}, "f14"}, {{"fa5"}, "f15"},
+ {{"fa6"}, "f16"}, {{"fa7"}, "f17"}, {{"fs2"}, "f18"}, {{"fs3"}, "f19"},
+ {{"fs4"}, "f20"}, {{"fs5"}, "f21"}, {{"fs6"}, "f22"}, {{"fs7"}, "f23"},
+ {{"fs8"}, "f24"}, {{"fs9"}, "f25"}, {{"fs10"}, "f26"}, {{"fs11"}, "f27"},
+ {{"ft8"}, "f28"}, {{"ft9"}, "f29"}, {{"ft10"}, "f30"}, {{"ft11"}, "f31"}};
return llvm::makeArrayRef(GCCRegAliases);
}
@@ -56,6 +71,14 @@ bool RISCVTargetInfo::validateAsmConstraint(
// A 5-bit unsigned immediate for CSR access instructions.
Info.setRequiresImmediate(0, 31);
return true;
+ case 'f':
+ // A floating-point register.
+ Info.setAllowsRegister();
+ return true;
+ case 'A':
+ // An address that is held in a general-purpose register.
+ Info.setAllowsMemory();
+ return true;
}
}
@@ -65,9 +88,25 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__riscv");
bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64;
Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
- // TODO: modify when more code models and ABIs are supported.
- Builder.defineMacro("__riscv_cmodel_medlow");
- Builder.defineMacro("__riscv_float_abi_soft");
+ StringRef CodeModel = getTargetOpts().CodeModel;
+ if (CodeModel == "default")
+ CodeModel = "small";
+
+ if (CodeModel == "small")
+ Builder.defineMacro("__riscv_cmodel_medlow");
+ else if (CodeModel == "medium")
+ Builder.defineMacro("__riscv_cmodel_medany");
+
+ StringRef ABIName = getABI();
+ if (ABIName == "ilp32f" || ABIName == "lp64f")
+ Builder.defineMacro("__riscv_float_abi_single");
+ else if (ABIName == "ilp32d" || ABIName == "lp64d")
+ Builder.defineMacro("__riscv_float_abi_double");
+ else
+ Builder.defineMacro("__riscv_float_abi_soft");
+
+ if (ABIName == "ilp32e")
+ Builder.defineMacro("__riscv_abi_rve");
if (HasM) {
Builder.defineMacro("__riscv_mul");
diff --git a/lib/Basic/Targets/RISCV.h b/lib/Basic/Targets/RISCV.h
index bc814b79ce51..9118494a87ab 100644
--- a/lib/Basic/Targets/RISCV.h
+++ b/lib/Basic/Targets/RISCV.h
@@ -87,13 +87,19 @@ public:
}
bool setABI(const std::string &Name) override {
- // TODO: support ilp32f and ilp32d ABIs.
- if (Name == "ilp32") {
+ if (Name == "ilp32" || Name == "ilp32f" || Name == "ilp32d") {
ABI = Name;
return true;
}
return false;
}
+
+ void setMaxAtomicWidth() override {
+ MaxAtomicPromoteWidth = 128;
+
+ if (HasA)
+ MaxAtomicInlineWidth = 32;
+ }
};
class LLVM_LIBRARY_VISIBILITY RISCV64TargetInfo : public RISCVTargetInfo {
public:
@@ -105,13 +111,19 @@ public:
}
bool setABI(const std::string &Name) override {
- // TODO: support lp64f and lp64d ABIs.
- if (Name == "lp64") {
+ if (Name == "lp64" || Name == "lp64f" || Name == "lp64d") {
ABI = Name;
return true;
}
return false;
}
+
+ void setMaxAtomicWidth() override {
+ MaxAtomicPromoteWidth = 128;
+
+ if (HasA)
+ MaxAtomicInlineWidth = 64;
+ }
};
} // namespace targets
} // namespace clang
diff --git a/lib/Basic/Targets/SPIR.h b/lib/Basic/Targets/SPIR.h
index 6023c868dbdc..802ccf8b671e 100644
--- a/lib/Basic/Targets/SPIR.h
+++ b/lib/Basic/Targets/SPIR.h
@@ -88,7 +88,7 @@ public:
: CCCR_Warning;
}
- CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override {
+ CallingConv getDefaultCallingConv() const override {
return CC_SpirFunction;
}
diff --git a/lib/Basic/Targets/Sparc.h b/lib/Basic/Targets/Sparc.h
index 963192a4634f..1f799565e99b 100644
--- a/lib/Basic/Targets/Sparc.h
+++ b/lib/Basic/Targets/Sparc.h
@@ -208,6 +208,7 @@ public:
// aligned. The SPARCv9 SCD 2.4.1 says 16-byte aligned.
LongDoubleWidth = 128;
LongDoubleAlign = 128;
+ SuitableAlign = 128;
LongDoubleFormat = &llvm::APFloat::IEEEquad();
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
}
diff --git a/lib/Basic/Targets/SystemZ.cpp b/lib/Basic/Targets/SystemZ.cpp
index d86928a6333b..ad3915e4d5dd 100644
--- a/lib/Basic/Targets/SystemZ.cpp
+++ b/lib/Basic/Targets/SystemZ.cpp
@@ -92,7 +92,7 @@ static constexpr ISANameRevision ISARevisions[] = {
{{"arch10"}, 10}, {{"zEC12"}, 10},
{{"arch11"}, 11}, {{"z13"}, 11},
{{"arch12"}, 12}, {{"z14"}, 12},
- {{"arch13"}, 13},
+ {{"arch13"}, 13}, {{"z15"}, 13}
};
int SystemZTargetInfo::getISARevision(StringRef Name) const {
diff --git a/lib/Basic/Targets/X86.cpp b/lib/Basic/Targets/X86.cpp
index d618c90b05c0..311ae6e17028 100644
--- a/lib/Basic/Targets/X86.cpp
+++ b/lib/Basic/Targets/X86.cpp
@@ -157,11 +157,20 @@ bool X86TargetInfo::initFeatureMap(
// SkylakeServer cores inherits all SKL features, except SGX
goto SkylakeCommon;
+ case CK_Tigerlake:
+ setFeatureEnabledImpl(Features, "avx512vp2intersect", true);
+ setFeatureEnabledImpl(Features, "movdiri", true);
+ setFeatureEnabledImpl(Features, "movdir64b", true);
+ setFeatureEnabledImpl(Features, "shstk", true);
+ // Tigerlake cores inherits IcelakeClient, except pconfig and wbnoinvd
+ goto IcelakeCommon;
+
case CK_IcelakeServer:
setFeatureEnabledImpl(Features, "pconfig", true);
setFeatureEnabledImpl(Features, "wbnoinvd", true);
LLVM_FALLTHROUGH;
case CK_IcelakeClient:
+IcelakeCommon:
setFeatureEnabledImpl(Features, "vaes", true);
setFeatureEnabledImpl(Features, "gfni", true);
setFeatureEnabledImpl(Features, "vpclmulqdq", true);
@@ -189,7 +198,6 @@ bool X86TargetInfo::initFeatureMap(
SkylakeCommon:
setFeatureEnabledImpl(Features, "xsavec", true);
setFeatureEnabledImpl(Features, "xsaves", true);
- setFeatureEnabledImpl(Features, "mpx", true);
setFeatureEnabledImpl(Features, "clflushopt", true);
setFeatureEnabledImpl(Features, "aes", true);
LLVM_FALLTHROUGH;
@@ -268,7 +276,6 @@ SkylakeCommon:
setFeatureEnabledImpl(Features, "xsavec", true);
setFeatureEnabledImpl(Features, "xsaves", true);
setFeatureEnabledImpl(Features, "clflushopt", true);
- setFeatureEnabledImpl(Features, "mpx", true);
setFeatureEnabledImpl(Features, "fsgsbase", true);
setFeatureEnabledImpl(Features, "aes", true);
LLVM_FALLTHROUGH;
@@ -789,8 +796,6 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasAVX512VP2INTERSECT = true;
} else if (Feature == "+sha") {
HasSHA = true;
- } else if (Feature == "+mpx") {
- HasMPX = true;
} else if (Feature == "+shstk") {
HasSHSTK = true;
} else if (Feature == "+movbe") {
@@ -895,7 +900,7 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
/// definitions for this particular subtarget.
void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
- // Inline assembly supports X86 flag outputs.
+ // Inline assembly supports X86 flag outputs.
Builder.defineMacro("__GCC_ASM_FLAG_OUTPUTS__");
std::string CodeModel = getTargetOpts().CodeModel;
@@ -1000,6 +1005,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case CK_Cannonlake:
case CK_IcelakeClient:
case CK_IcelakeServer:
+ case CK_Tigerlake:
// FIXME: Historically, we defined this legacy name, it would be nice to
// remove it at some point. We've never exposed fine-grained names for
// recent primary x86 CPUs, and we should keep it that way.
@@ -1210,8 +1216,6 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__CLWB__");
if (HasWBNOINVD)
Builder.defineMacro("__WBNOINVD__");
- if (HasMPX)
- Builder.defineMacro("__MPX__");
if (HasSHSTK)
Builder.defineMacro("__SHSTK__");
if (HasSGX)
@@ -1368,7 +1372,6 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const {
.Case("movbe", true)
.Case("movdiri", true)
.Case("movdir64b", true)
- .Case("mpx", true)
.Case("mwaitx", true)
.Case("pclmul", true)
.Case("pconfig", true)
@@ -1452,7 +1455,6 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("movbe", HasMOVBE)
.Case("movdiri", HasMOVDIRI)
.Case("movdir64b", HasMOVDIR64B)
- .Case("mpx", HasMPX)
.Case("mwaitx", HasMWAITX)
.Case("pclmul", HasPCLMUL)
.Case("pconfig", HasPCONFIG)
diff --git a/lib/Basic/Targets/X86.h b/lib/Basic/Targets/X86.h
index 588b6d3da1d6..cad869f71230 100644
--- a/lib/Basic/Targets/X86.h
+++ b/lib/Basic/Targets/X86.h
@@ -80,7 +80,6 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
bool HasAVX512IFMA = false;
bool HasAVX512VP2INTERSECT = false;
bool HasSHA = false;
- bool HasMPX = false;
bool HasSHSTK = false;
bool HasSGX = false;
bool HasCX8 = false;
@@ -320,8 +319,8 @@ public:
}
}
- CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override {
- return MT == CCMT_Member ? CC_X86ThisCall : CC_C;
+ CallingConv getDefaultCallingConv() const override {
+ return CC_C;
}
bool hasSjLjLowering() const override { return true; }
@@ -340,7 +339,8 @@ public:
LongDoubleWidth = 96;
LongDoubleAlign = 32;
SuitableAlign = 128;
- resetDataLayout("e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128");
+ resetDataLayout("e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-"
+ "f80:32-n8:16:32-S128");
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
IntPtrType = SignedInt;
@@ -440,7 +440,8 @@ public:
UseSignedCharForObjCBool = false;
SizeType = UnsignedLong;
IntPtrType = SignedLong;
- resetDataLayout("e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128");
+ resetDataLayout("e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-"
+ "f80:128-n8:16:32-S128");
HasAlignMac68kSupport = true;
}
@@ -465,9 +466,10 @@ public:
DoubleAlign = LongLongAlign = 64;
bool IsWinCOFF =
getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF();
- resetDataLayout(IsWinCOFF
- ? "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
- : "e-m:e-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32");
+ resetDataLayout(IsWinCOFF ? "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:"
+ "64-i64:64-f80:32-n8:16:32-a:0:32-S32"
+ : "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:"
+ "64-i64:64-f80:32-n8:16:32-a:0:32-S32");
}
};
@@ -515,7 +517,8 @@ public:
: X86_32TargetInfo(Triple, Opts) {
this->WCharType = TargetInfo::UnsignedShort;
DoubleAlign = LongLongAlign = 64;
- resetDataLayout("e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32");
+ resetDataLayout("e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:"
+ "32-n8:16:32-a:0:32-S32");
}
void getTargetDefines(const LangOptions &Opts,
@@ -552,7 +555,8 @@ public:
: X86_32TargetInfo(Triple, Opts) {
LongDoubleWidth = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble();
- resetDataLayout("e-m:e-p:32:32-i64:32-f64:32-f128:32-n8:16:32-a:0:32-S32");
+ resetDataLayout("e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:32-f64:"
+ "32-f128:32-n8:16:32-a:0:32-S32");
WIntType = UnsignedInt;
}
@@ -611,10 +615,12 @@ public:
RegParmMax = 6;
// Pointers are 32-bit in x32.
- resetDataLayout(IsX32
- ? "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128"
- : IsWinCOFF ? "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
- : "e-m:e-i64:64-f80:128-n8:16:32:64-S128");
+ resetDataLayout(IsX32 ? "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-"
+ "i64:64-f80:128-n8:16:32:64-S128"
+ : IsWinCOFF ? "e-m:w-p270:32:32-p271:32:32-p272:64:"
+ "64-i64:64-f80:128-n8:16:32:64-S128"
+ : "e-m:e-p270:32:32-p271:32:32-p272:64:"
+ "64-i64:64-f80:128-n8:16:32:64-S128");
// Use fpret only for long double.
RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble);
@@ -659,7 +665,7 @@ public:
}
}
- CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override {
+ CallingConv getDefaultCallingConv() const override {
return CC_C;
}
@@ -804,7 +810,8 @@ public:
llvm::Triple T = llvm::Triple(Triple);
if (T.isiOS())
UseSignedCharForObjCBool = false;
- resetDataLayout("e-m:o-i64:64-f80:128-n8:16:32:64-S128");
+ resetDataLayout("e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:"
+ "16:32:64-S128");
}
bool handleTargetFeatures(std::vector<std::string> &Features,
diff --git a/lib/Basic/TokenKinds.cpp b/lib/Basic/TokenKinds.cpp
index a71cd72517de..d55e176c72c4 100644
--- a/lib/Basic/TokenKinds.cpp
+++ b/lib/Basic/TokenKinds.cpp
@@ -45,3 +45,23 @@ const char *tok::getKeywordSpelling(TokenKind Kind) {
}
return nullptr;
}
+
+bool tok::isAnnotation(TokenKind Kind) {
+ switch (Kind) {
+#define ANNOTATION(X) case annot_ ## X: return true;
+#include "clang/Basic/TokenKinds.def"
+ default:
+ break;
+ }
+ return false;
+}
+
+bool tok::isPragmaAnnotation(TokenKind Kind) {
+ switch (Kind) {
+#define PRAGMA_ANNOTATION(X) case annot_ ## X: return true;
+#include "clang/Basic/TokenKinds.def"
+ default:
+ break;
+ }
+ return false;
+}
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 497652e85b47..75a54d8f3c8a 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -37,6 +37,7 @@
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
+#include "llvm/Passes/StandardInstrumentations.h"
#include "llvm/Support/BuryPointer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -60,6 +61,7 @@
#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
#include "llvm/Transforms/Instrumentation/InstrProfiling.h"
#include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
+#include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar.h"
@@ -117,8 +119,8 @@ class EmitAssemblyHelper {
std::unique_ptr<llvm::ToolOutputFile> openOutputFile(StringRef Path) {
std::error_code EC;
- auto F = llvm::make_unique<llvm::ToolOutputFile>(Path, EC,
- llvm::sys::fs::F_None);
+ auto F = std::make_unique<llvm::ToolOutputFile>(Path, EC,
+ llvm::sys::fs::OF_None);
if (EC) {
Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
F.reset();
@@ -195,11 +197,8 @@ static void addBoundsCheckingPass(const PassManagerBuilder &Builder,
PM.add(createBoundsCheckingLegacyPass());
}
-static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
- legacy::PassManagerBase &PM) {
- const PassManagerBuilderWrapper &BuilderWrapper =
- static_cast<const PassManagerBuilderWrapper&>(Builder);
- const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
+static SanitizerCoverageOptions
+getSancovOptsFromCGOpts(const CodeGenOptions &CGOpts) {
SanitizerCoverageOptions Opts;
Opts.CoverageType =
static_cast<SanitizerCoverageOptions::Type>(CGOpts.SanitizeCoverageType);
@@ -215,7 +214,16 @@ static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
Opts.Inline8bitCounters = CGOpts.SanitizeCoverageInline8bitCounters;
Opts.PCTable = CGOpts.SanitizeCoveragePCTable;
Opts.StackDepth = CGOpts.SanitizeCoverageStackDepth;
- PM.add(createSanitizerCoverageModulePass(Opts));
+ return Opts;
+}
+
+static void addSanitizerCoveragePass(const PassManagerBuilder &Builder,
+ legacy::PassManagerBase &PM) {
+ const PassManagerBuilderWrapper &BuilderWrapper =
+ static_cast<const PassManagerBuilderWrapper &>(Builder);
+ const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
+ auto Opts = getSancovOptsFromCGOpts(CGOpts);
+ PM.add(createModuleSanitizerCoverageLegacyPassPass(Opts));
}
// Check if ASan should use GC-friendly instrumentation for globals.
@@ -231,9 +239,13 @@ static bool asanUseGlobalsGC(const Triple &T, const CodeGenOptions &CGOpts) {
return true;
case Triple::ELF:
return CGOpts.DataSections && !CGOpts.DisableIntegratedAS;
- default:
- return false;
+ case Triple::XCOFF:
+ llvm::report_fatal_error("ASan not implemented for XCOFF.");
+ case Triple::Wasm:
+ case Triple::UnknownObjectFormat:
+ break;
}
+ return false;
}
static void addAddressSanitizerPasses(const PassManagerBuilder &Builder,
@@ -456,6 +468,8 @@ static void initTargetOptions(llvm::TargetOptions &Options,
Options.ExceptionModel = llvm::ExceptionHandling::WinEH;
if (LangOpts.DWARFExceptions)
Options.ExceptionModel = llvm::ExceptionHandling::DwarfCFI;
+ if (LangOpts.WasmExceptions)
+ Options.ExceptionModel = llvm::ExceptionHandling::Wasm;
Options.NoInfsFPMath = CodeGenOpts.NoInfsFPMath;
Options.NoNaNsFPMath = CodeGenOpts.NoNaNsFPMath;
@@ -481,6 +495,7 @@ static void initTargetOptions(llvm::TargetOptions &Options,
CodeGenOpts.IncrementalLinkerCompatible;
Options.MCOptions.MCPIECopyRelocations = CodeGenOpts.PIECopyRelocations;
Options.MCOptions.MCFatalWarnings = CodeGenOpts.FatalWarnings;
+ Options.MCOptions.MCNoWarn = CodeGenOpts.NoWarn;
Options.MCOptions.AsmVerbose = CodeGenOpts.AsmVerbose;
Options.MCOptions.PreserveAsmComments = CodeGenOpts.PreserveAsmComments;
Options.MCOptions.ABIName = TargetOpts.ABI;
@@ -848,7 +863,7 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
if (!TheModule->getModuleFlag("ThinLTO"))
TheModule->addModuleFlag(Module::Error, "ThinLTO", uint32_t(0));
TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit",
- CodeGenOpts.EnableSplitLTOUnit);
+ uint32_t(1));
}
PerModulePasses.add(createBitcodeWriterPass(
@@ -880,6 +895,7 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
{
PrettyStackTraceString CrashInfo("Per-function optimization");
+ llvm::TimeTraceScope TimeScope("PerFunctionPasses", StringRef(""));
PerFunctionPasses.doInitialization();
for (Function &F : *TheModule)
@@ -890,11 +906,13 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
{
PrettyStackTraceString CrashInfo("Per-module optimization passes");
+ llvm::TimeTraceScope TimeScope("PerModulePasses", StringRef(""));
PerModulePasses.run(*TheModule);
}
{
PrettyStackTraceString CrashInfo("Code generation");
+ llvm::TimeTraceScope TimeScope("CodeGenPasses", StringRef(""));
CodeGenPasses.run(*TheModule);
}
@@ -956,6 +974,7 @@ static void addSanitizersAtO0(ModulePassManager &MPM,
}
if (LangOpts.Sanitize.has(SanitizerKind::Memory)) {
+ MPM.addPass(MemorySanitizerPass({}));
MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass({})));
}
@@ -965,6 +984,7 @@ static void addSanitizersAtO0(ModulePassManager &MPM,
}
if (LangOpts.Sanitize.has(SanitizerKind::Thread)) {
+ MPM.addPass(ThreadSanitizerPass());
MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
}
}
@@ -1050,7 +1070,10 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
PTO.LoopVectorization = CodeGenOpts.VectorizeLoop;
PTO.SLPVectorization = CodeGenOpts.VectorizeSLP;
- PassBuilder PB(TM.get(), PTO, PGOOpt);
+ PassInstrumentationCallbacks PIC;
+ StandardInstrumentations SI;
+ SI.registerCallbacks(PIC);
+ PassBuilder PB(TM.get(), PTO, PGOOpt, &PIC);
// Attempt to load pass plugins and register their callbacks with PB.
for (auto &PluginFN : CodeGenOpts.PassPlugins) {
@@ -1077,7 +1100,6 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
std::unique_ptr<TargetLibraryInfoImpl> TLII(
createTLII(TargetTriple, CodeGenOpts));
FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
- MAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
// Register all the basic analyses with the managers.
PB.registerModuleAnalyses(MAM);
@@ -1105,6 +1127,16 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
// code generation.
MPM.addPass(AlwaysInlinerPass(/*InsertLifetimeIntrinsics=*/false));
+ // At -O0, we can still do PGO. Add all the requested passes for
+ // instrumentation PGO, if requested.
+ if (PGOOpt && (PGOOpt->Action == PGOOptions::IRInstr ||
+ PGOOpt->Action == PGOOptions::IRUse))
+ PB.addPGOInstrPassesForO0(
+ MPM, CodeGenOpts.DebugPassManager,
+ /* RunProfileGen */ (PGOOpt->Action == PGOOptions::IRInstr),
+ /* IsCS */ false, PGOOpt->ProfileFile,
+ PGOOpt->ProfileRemappingFile);
+
// At -O0 we directly run necessary sanitizer passes.
if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds))
MPM.addPass(createModuleToFunctionPassAdaptor(BoundsCheckingPass()));
@@ -1132,16 +1164,23 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
[](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
FPM.addPass(BoundsCheckingPass());
});
- if (LangOpts.Sanitize.has(SanitizerKind::Memory))
+ if (LangOpts.Sanitize.has(SanitizerKind::Memory)) {
+ PB.registerPipelineStartEPCallback([](ModulePassManager &MPM) {
+ MPM.addPass(MemorySanitizerPass({}));
+ });
PB.registerOptimizerLastEPCallback(
[](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
FPM.addPass(MemorySanitizerPass({}));
});
- if (LangOpts.Sanitize.has(SanitizerKind::Thread))
+ }
+ if (LangOpts.Sanitize.has(SanitizerKind::Thread)) {
+ PB.registerPipelineStartEPCallback(
+ [](ModulePassManager &MPM) { MPM.addPass(ThreadSanitizerPass()); });
PB.registerOptimizerLastEPCallback(
[](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
FPM.addPass(ThreadSanitizerPass());
});
+ }
if (LangOpts.Sanitize.has(SanitizerKind::Address)) {
PB.registerPipelineStartEPCallback([&](ModulePassManager &MPM) {
MPM.addPass(
@@ -1191,6 +1230,13 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
}
}
+ if (CodeGenOpts.SanitizeCoverageType ||
+ CodeGenOpts.SanitizeCoverageIndirectCalls ||
+ CodeGenOpts.SanitizeCoverageTraceCmp) {
+ auto SancovOpts = getSancovOptsFromCGOpts(CodeGenOpts);
+ MPM.addPass(ModuleSanitizerCoveragePass(SancovOpts));
+ }
+
if (LangOpts.Sanitize.has(SanitizerKind::HWAddress)) {
bool Recover = CodeGenOpts.SanitizeRecover.has(SanitizerKind::HWAddress);
MPM.addPass(HWAddressSanitizerPass(
@@ -1201,8 +1247,9 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
/*CompileKernel=*/true, /*Recover=*/true));
}
- if (CodeGenOpts.OptimizationLevel == 0)
+ if (CodeGenOpts.OptimizationLevel == 0) {
addSanitizersAtO0(MPM, TargetTriple, LangOpts, CodeGenOpts);
+ }
}
// FIXME: We still use the legacy pass manager to do code generation. We
@@ -1239,7 +1286,7 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager(
if (!TheModule->getModuleFlag("ThinLTO"))
TheModule->addModuleFlag(Module::Error, "ThinLTO", uint32_t(0));
TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit",
- CodeGenOpts.EnableSplitLTOUnit);
+ uint32_t(1));
}
MPM.addPass(
BitcodeWriterPass(*OS, CodeGenOpts.EmitLLVMUseLists, EmitLTOSummary));
@@ -1372,7 +1419,7 @@ static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M,
OwnedImports.push_back(std::move(*MBOrErr));
}
auto AddStream = [&](size_t Task) {
- return llvm::make_unique<lto::NativeObjectStream>(std::move(OS));
+ return std::make_unique<lto::NativeObjectStream>(std::move(OS));
};
lto::Config Conf;
if (CGOpts.SaveTempsFilePrefix != "") {
@@ -1484,7 +1531,7 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
// trying to read it. Also for some features, like CFI, we must skip
// the compilation as CombinedIndex does not contain all required
// information.
- EmptyModule = llvm::make_unique<llvm::Module>("empty", M->getContext());
+ EmptyModule = std::make_unique<llvm::Module>("empty", M->getContext());
EmptyModule->setTargetTriple(M->getTargetTriple());
M = EmptyModule.get();
}
diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp
index a95cd12c2d64..505916350750 100644
--- a/lib/CodeGen/CGAtomic.cpp
+++ b/lib/CodeGen/CGAtomic.cpp
@@ -102,12 +102,13 @@ namespace {
llvm::APInt Size(
/*numBits=*/32,
C.toCharUnitsFromBits(AtomicSizeInBits).getQuantity());
- AtomicTy = C.getConstantArrayType(C.CharTy, Size, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
+ AtomicTy =
+ C.getConstantArrayType(C.CharTy, Size, nullptr, ArrayType::Normal,
+ /*IndexTypeQuals=*/0);
}
AtomicAlign = ValueAlign = lvalue.getAlignment();
} else if (lvalue.isVectorElt()) {
- ValueTy = lvalue.getType()->getAs<VectorType>()->getElementType();
+ ValueTy = lvalue.getType()->castAs<VectorType>()->getElementType();
ValueSizeInBits = C.getTypeSize(ValueTy);
AtomicTy = lvalue.getType();
AtomicSizeInBits = C.getTypeSize(AtomicTy);
@@ -969,7 +970,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) {
auto CastToGenericAddrSpace = [&](llvm::Value *V, QualType PT) {
if (!E->isOpenCL())
return V;
- auto AS = PT->getAs<PointerType>()->getPointeeType().getAddressSpace();
+ auto AS = PT->castAs<PointerType>()->getPointeeType().getAddressSpace();
if (AS == LangAS::opencl_generic)
return V;
auto DestAS = getContext().getTargetAddressSpace(LangAS::opencl_generic);
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index c3ee7129d9d7..f90d9439af25 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -1253,8 +1253,7 @@ llvm::Type *CodeGenModule::getGenericBlockLiteralType() {
RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue) {
- const BlockPointerType *BPT =
- E->getCallee()->getType()->getAs<BlockPointerType>();
+ const auto *BPT = E->getCallee()->getType()->castAs<BlockPointerType>();
llvm::Value *BlockPtr = EmitScalarExpr(E->getCallee());
llvm::Type *GenBlockTy = CGM.getGenericBlockLiteralType();
llvm::Value *Func = nullptr;
@@ -1802,7 +1801,7 @@ struct CallBlockRelease final : EHScopeStack::Cleanup {
bool CodeGenFunction::cxxDestructorCanThrow(QualType T) {
if (const auto *RD = T->getAsCXXRecordDecl())
if (const CXXDestructorDecl *DD = RD->getDestructor())
- return DD->getType()->getAs<FunctionProtoType>()->canThrow();
+ return DD->getType()->castAs<FunctionProtoType>()->canThrow();
return false;
}
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index a300bab49f9c..f9871b233149 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -843,10 +843,12 @@ static RValue EmitMSVCRTSetJmp(CodeGenFunction &CGF, MSVCSetJmpKind SJKind,
Name = SJKind == MSVCSetJmpKind::_setjmp ? "_setjmp" : "_setjmpex";
Arg1Ty = CGF.Int8PtrTy;
if (CGF.getTarget().getTriple().getArch() == llvm::Triple::aarch64) {
- Arg1 = CGF.Builder.CreateCall(CGF.CGM.getIntrinsic(Intrinsic::sponentry));
+ Arg1 = CGF.Builder.CreateCall(
+ CGF.CGM.getIntrinsic(Intrinsic::sponentry, CGF.AllocaInt8PtrTy));
} else
- Arg1 = CGF.Builder.CreateCall(CGF.CGM.getIntrinsic(Intrinsic::frameaddress),
- llvm::ConstantInt::get(CGF.Int32Ty, 0));
+ Arg1 = CGF.Builder.CreateCall(
+ CGF.CGM.getIntrinsic(Intrinsic::frameaddress, CGF.AllocaInt8PtrTy),
+ llvm::ConstantInt::get(CGF.Int32Ty, 0));
}
// Mark the call site and declaration with ReturnsTwice.
@@ -1394,9 +1396,8 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1,
static llvm::Value *dumpRecord(CodeGenFunction &CGF, QualType RType,
Value *&RecordPtr, CharUnits Align,
llvm::FunctionCallee Func, int Lvl) {
- const auto *RT = RType->getAs<RecordType>();
ASTContext &Context = CGF.getContext();
- RecordDecl *RD = RT->getDecl()->getDefinition();
+ RecordDecl *RD = RType->castAs<RecordType>()->getDecl()->getDefinition();
std::string Pad = std::string(Lvl * 4, ' ');
Value *GString =
@@ -1555,6 +1556,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIceill:
case Builtin::BI__builtin_ceil:
case Builtin::BI__builtin_ceilf:
+ case Builtin::BI__builtin_ceilf16:
case Builtin::BI__builtin_ceill:
return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::ceil));
@@ -1563,6 +1565,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIcopysignl:
case Builtin::BI__builtin_copysign:
case Builtin::BI__builtin_copysignf:
+ case Builtin::BI__builtin_copysignf16:
case Builtin::BI__builtin_copysignl:
case Builtin::BI__builtin_copysignf128:
return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::copysign));
@@ -1572,6 +1575,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIcosl:
case Builtin::BI__builtin_cos:
case Builtin::BI__builtin_cosf:
+ case Builtin::BI__builtin_cosf16:
case Builtin::BI__builtin_cosl:
return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::cos));
@@ -1580,6 +1584,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIexpl:
case Builtin::BI__builtin_exp:
case Builtin::BI__builtin_expf:
+ case Builtin::BI__builtin_expf16:
case Builtin::BI__builtin_expl:
return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::exp));
@@ -1588,6 +1593,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIexp2l:
case Builtin::BI__builtin_exp2:
case Builtin::BI__builtin_exp2f:
+ case Builtin::BI__builtin_exp2f16:
case Builtin::BI__builtin_exp2l:
return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::exp2));
@@ -1596,6 +1602,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIfabsl:
case Builtin::BI__builtin_fabs:
case Builtin::BI__builtin_fabsf:
+ case Builtin::BI__builtin_fabsf16:
case Builtin::BI__builtin_fabsl:
case Builtin::BI__builtin_fabsf128:
return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::fabs));
@@ -1605,6 +1612,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIfloorl:
case Builtin::BI__builtin_floor:
case Builtin::BI__builtin_floorf:
+ case Builtin::BI__builtin_floorf16:
case Builtin::BI__builtin_floorl:
return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::floor));
@@ -1613,6 +1621,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIfmal:
case Builtin::BI__builtin_fma:
case Builtin::BI__builtin_fmaf:
+ case Builtin::BI__builtin_fmaf16:
case Builtin::BI__builtin_fmal:
return RValue::get(emitTernaryBuiltin(*this, E, Intrinsic::fma));
@@ -1621,6 +1630,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIfmaxl:
case Builtin::BI__builtin_fmax:
case Builtin::BI__builtin_fmaxf:
+ case Builtin::BI__builtin_fmaxf16:
case Builtin::BI__builtin_fmaxl:
return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::maxnum));
@@ -1629,6 +1639,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIfminl:
case Builtin::BI__builtin_fmin:
case Builtin::BI__builtin_fminf:
+ case Builtin::BI__builtin_fminf16:
case Builtin::BI__builtin_fminl:
return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::minnum));
@@ -1639,6 +1650,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIfmodl:
case Builtin::BI__builtin_fmod:
case Builtin::BI__builtin_fmodf:
+ case Builtin::BI__builtin_fmodf16:
case Builtin::BI__builtin_fmodl: {
Value *Arg1 = EmitScalarExpr(E->getArg(0));
Value *Arg2 = EmitScalarExpr(E->getArg(1));
@@ -1650,6 +1662,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIlogl:
case Builtin::BI__builtin_log:
case Builtin::BI__builtin_logf:
+ case Builtin::BI__builtin_logf16:
case Builtin::BI__builtin_logl:
return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log));
@@ -1658,6 +1671,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIlog10l:
case Builtin::BI__builtin_log10:
case Builtin::BI__builtin_log10f:
+ case Builtin::BI__builtin_log10f16:
case Builtin::BI__builtin_log10l:
return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log10));
@@ -1666,6 +1680,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIlog2l:
case Builtin::BI__builtin_log2:
case Builtin::BI__builtin_log2f:
+ case Builtin::BI__builtin_log2f16:
case Builtin::BI__builtin_log2l:
return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log2));
@@ -1682,6 +1697,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIpowl:
case Builtin::BI__builtin_pow:
case Builtin::BI__builtin_powf:
+ case Builtin::BI__builtin_powf16:
case Builtin::BI__builtin_powl:
return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::pow));
@@ -1690,6 +1706,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIrintl:
case Builtin::BI__builtin_rint:
case Builtin::BI__builtin_rintf:
+ case Builtin::BI__builtin_rintf16:
case Builtin::BI__builtin_rintl:
return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::rint));
@@ -1698,6 +1715,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIroundl:
case Builtin::BI__builtin_round:
case Builtin::BI__builtin_roundf:
+ case Builtin::BI__builtin_roundf16:
case Builtin::BI__builtin_roundl:
return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::round));
@@ -1706,6 +1724,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIsinl:
case Builtin::BI__builtin_sin:
case Builtin::BI__builtin_sinf:
+ case Builtin::BI__builtin_sinf16:
case Builtin::BI__builtin_sinl:
return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sin));
@@ -1714,6 +1733,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIsqrtl:
case Builtin::BI__builtin_sqrt:
case Builtin::BI__builtin_sqrtf:
+ case Builtin::BI__builtin_sqrtf16:
case Builtin::BI__builtin_sqrtl:
return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sqrt));
@@ -1722,6 +1742,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BItruncl:
case Builtin::BI__builtin_trunc:
case Builtin::BI__builtin_truncf:
+ case Builtin::BI__builtin_truncf16:
case Builtin::BI__builtin_truncl:
return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::trunc));
@@ -2026,11 +2047,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Value *AlignmentValue = EmitScalarExpr(E->getArg(1));
ConstantInt *AlignmentCI = cast<ConstantInt>(AlignmentValue);
- unsigned Alignment = (unsigned)AlignmentCI->getZExtValue();
+ if (AlignmentCI->getValue().ugt(llvm::Value::MaximumAlignment))
+ AlignmentCI = ConstantInt::get(AlignmentCI->getType(),
+ llvm::Value::MaximumAlignment);
EmitAlignmentAssumption(PtrValue, Ptr,
/*The expr loc is sufficient.*/ SourceLocation(),
- Alignment, OffsetValue);
+ AlignmentCI, OffsetValue);
return RValue::get(PtrValue);
}
case Builtin::BI__assume:
@@ -2077,10 +2100,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_constant_p: {
llvm::Type *ResultType = ConvertType(E->getType());
- if (CGM.getCodeGenOpts().OptimizationLevel == 0)
- // At -O0, we don't perform inlining, so we don't need to delay the
- // processing.
- return RValue::get(ConstantInt::get(ResultType, 0));
const Expr *Arg = E->getArg(0);
QualType ArgType = Arg->getType();
@@ -2131,7 +2150,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Locality = (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) :
llvm::ConstantInt::get(Int32Ty, 3);
Value *Data = llvm::ConstantInt::get(Int32Ty, 1);
- Function *F = CGM.getIntrinsic(Intrinsic::prefetch);
+ Function *F = CGM.getIntrinsic(Intrinsic::prefetch, Address->getType());
return RValue::get(Builder.CreateCall(F, {Address, RW, Locality, Data}));
}
case Builtin::BI__builtin_readcyclecounter: {
@@ -2344,7 +2363,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
.toCharUnitsFromBits(TI.getSuitableAlign())
.getQuantity();
AllocaInst *AI = Builder.CreateAlloca(Builder.getInt8Ty(), Size);
- AI->setAlignment(SuitableAlignmentInBytes);
+ AI->setAlignment(MaybeAlign(SuitableAlignmentInBytes));
initializeAlloca(*this, AI, Size, SuitableAlignmentInBytes);
return RValue::get(AI);
}
@@ -2357,7 +2376,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
unsigned AlignmentInBytes =
CGM.getContext().toCharUnitsFromBits(AlignmentInBits).getQuantity();
AllocaInst *AI = Builder.CreateAlloca(Builder.getInt8Ty(), Size);
- AI->setAlignment(AlignmentInBytes);
+ AI->setAlignment(MaybeAlign(AlignmentInBytes));
initializeAlloca(*this, AI, Size, AlignmentInBytes);
return RValue::get(AI);
}
@@ -2556,7 +2575,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_frame_address: {
Value *Depth = ConstantEmitter(*this).emitAbstract(E->getArg(0),
getContext().UnsignedIntTy);
- Function *F = CGM.getIntrinsic(Intrinsic::frameaddress);
+ Function *F = CGM.getIntrinsic(Intrinsic::frameaddress, AllocaInt8PtrTy);
return RValue::get(Builder.CreateCall(F, Depth));
}
case Builtin::BI__builtin_extract_return_addr: {
@@ -2637,9 +2656,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Address Buf = EmitPointerWithAlignment(E->getArg(0));
// Store the frame pointer to the setjmp buffer.
- Value *FrameAddr =
- Builder.CreateCall(CGM.getIntrinsic(Intrinsic::frameaddress),
- ConstantInt::get(Int32Ty, 0));
+ Value *FrameAddr = Builder.CreateCall(
+ CGM.getIntrinsic(Intrinsic::frameaddress, AllocaInt8PtrTy),
+ ConstantInt::get(Int32Ty, 0));
Builder.CreateStore(FrameAddr, Buf);
// Store the stack pointer to the setjmp buffer.
@@ -3673,13 +3692,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BIget_pipe_num_packets:
case Builtin::BIget_pipe_max_packets: {
const char *BaseName;
- const PipeType *PipeTy = E->getArg(0)->getType()->getAs<PipeType>();
+ const auto *PipeTy = E->getArg(0)->getType()->castAs<PipeType>();
if (BuiltinID == Builtin::BIget_pipe_num_packets)
BaseName = "__get_pipe_num_packets";
else
BaseName = "__get_pipe_max_packets";
- auto Name = std::string(BaseName) +
- std::string(PipeTy->isReadOnly() ? "_ro" : "_wo");
+ std::string Name = std::string(BaseName) +
+ std::string(PipeTy->isReadOnly() ? "_ro" : "_wo");
// Building the generic function prototype.
Value *Arg0 = EmitScalarExpr(E->getArg(0));
@@ -3769,7 +3788,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
-> std::tuple<llvm::Value *, llvm::Value *, llvm::Value *> {
llvm::APInt ArraySize(32, NumArgs - First);
QualType SizeArrayTy = getContext().getConstantArrayType(
- getContext().getSizeType(), ArraySize, ArrayType::Normal,
+ getContext().getSizeType(), ArraySize, nullptr, ArrayType::Normal,
/*IndexTypeQuals=*/0);
auto Tmp = CreateMemTemp(SizeArrayTy, "block_sizes");
llvm::Value *TmpPtr = Tmp.getPointer();
@@ -3977,6 +3996,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
break;
case Builtin::BI__builtin_canonicalize:
case Builtin::BI__builtin_canonicalizef:
+ case Builtin::BI__builtin_canonicalizef16:
case Builtin::BI__builtin_canonicalizel:
return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::canonicalize));
@@ -4219,6 +4239,9 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF,
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
return CGF->EmitAArch64BuiltinExpr(BuiltinID, E, Arch);
+ case llvm::Triple::bpfeb:
+ case llvm::Triple::bpfel:
+ return CGF->EmitBPFBuiltinExpr(BuiltinID, E);
case llvm::Triple::x86:
case llvm::Triple::x86_64:
return CGF->EmitX86BuiltinExpr(BuiltinID, E);
@@ -6019,7 +6042,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
// Locality is not supported on ARM target
Value *Locality = llvm::ConstantInt::get(Int32Ty, 3);
- Function *F = CGM.getIntrinsic(Intrinsic::prefetch);
+ Function *F = CGM.getIntrinsic(Intrinsic::prefetch, Address->getType());
return Builder.CreateCall(F, {Address, RW, Locality, IsData});
}
@@ -6958,7 +6981,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
// FIXME: We need AArch64 specific LLVM intrinsic if we want to specify
// PLDL3STRM or PLDL2STRM.
- Function *F = CGM.getIntrinsic(Intrinsic::prefetch);
+ Function *F = CGM.getIntrinsic(Intrinsic::prefetch, Address->getType());
return Builder.CreateCall(F, {Address, RW, Locality, IsData});
}
@@ -7293,12 +7316,13 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
}
if (BuiltinID == AArch64::BI_AddressOfReturnAddress) {
- llvm::Function *F = CGM.getIntrinsic(Intrinsic::addressofreturnaddress);
+ llvm::Function *F =
+ CGM.getIntrinsic(Intrinsic::addressofreturnaddress, AllocaInt8PtrTy);
return Builder.CreateCall(F);
}
if (BuiltinID == AArch64::BI__builtin_sponentry) {
- llvm::Function *F = CGM.getIntrinsic(Intrinsic::sponentry);
+ llvm::Function *F = CGM.getIntrinsic(Intrinsic::sponentry, AllocaInt8PtrTy);
return Builder.CreateCall(F);
}
@@ -8011,6 +8035,151 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)),
"vgetq_lane");
}
+ case AArch64::BI_BitScanForward:
+ case AArch64::BI_BitScanForward64:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanForward, E);
+ case AArch64::BI_BitScanReverse:
+ case AArch64::BI_BitScanReverse64:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanReverse, E);
+ case AArch64::BI_InterlockedAnd64:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd, E);
+ case AArch64::BI_InterlockedExchange64:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange, E);
+ case AArch64::BI_InterlockedExchangeAdd64:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd, E);
+ case AArch64::BI_InterlockedExchangeSub64:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeSub, E);
+ case AArch64::BI_InterlockedOr64:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr, E);
+ case AArch64::BI_InterlockedXor64:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor, E);
+ case AArch64::BI_InterlockedDecrement64:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement, E);
+ case AArch64::BI_InterlockedIncrement64:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement, E);
+ case AArch64::BI_InterlockedExchangeAdd8_acq:
+ case AArch64::BI_InterlockedExchangeAdd16_acq:
+ case AArch64::BI_InterlockedExchangeAdd_acq:
+ case AArch64::BI_InterlockedExchangeAdd64_acq:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_acq, E);
+ case AArch64::BI_InterlockedExchangeAdd8_rel:
+ case AArch64::BI_InterlockedExchangeAdd16_rel:
+ case AArch64::BI_InterlockedExchangeAdd_rel:
+ case AArch64::BI_InterlockedExchangeAdd64_rel:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_rel, E);
+ case AArch64::BI_InterlockedExchangeAdd8_nf:
+ case AArch64::BI_InterlockedExchangeAdd16_nf:
+ case AArch64::BI_InterlockedExchangeAdd_nf:
+ case AArch64::BI_InterlockedExchangeAdd64_nf:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_nf, E);
+ case AArch64::BI_InterlockedExchange8_acq:
+ case AArch64::BI_InterlockedExchange16_acq:
+ case AArch64::BI_InterlockedExchange_acq:
+ case AArch64::BI_InterlockedExchange64_acq:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_acq, E);
+ case AArch64::BI_InterlockedExchange8_rel:
+ case AArch64::BI_InterlockedExchange16_rel:
+ case AArch64::BI_InterlockedExchange_rel:
+ case AArch64::BI_InterlockedExchange64_rel:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_rel, E);
+ case AArch64::BI_InterlockedExchange8_nf:
+ case AArch64::BI_InterlockedExchange16_nf:
+ case AArch64::BI_InterlockedExchange_nf:
+ case AArch64::BI_InterlockedExchange64_nf:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_nf, E);
+ case AArch64::BI_InterlockedCompareExchange8_acq:
+ case AArch64::BI_InterlockedCompareExchange16_acq:
+ case AArch64::BI_InterlockedCompareExchange_acq:
+ case AArch64::BI_InterlockedCompareExchange64_acq:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_acq, E);
+ case AArch64::BI_InterlockedCompareExchange8_rel:
+ case AArch64::BI_InterlockedCompareExchange16_rel:
+ case AArch64::BI_InterlockedCompareExchange_rel:
+ case AArch64::BI_InterlockedCompareExchange64_rel:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_rel, E);
+ case AArch64::BI_InterlockedCompareExchange8_nf:
+ case AArch64::BI_InterlockedCompareExchange16_nf:
+ case AArch64::BI_InterlockedCompareExchange_nf:
+ case AArch64::BI_InterlockedCompareExchange64_nf:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_nf, E);
+ case AArch64::BI_InterlockedOr8_acq:
+ case AArch64::BI_InterlockedOr16_acq:
+ case AArch64::BI_InterlockedOr_acq:
+ case AArch64::BI_InterlockedOr64_acq:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_acq, E);
+ case AArch64::BI_InterlockedOr8_rel:
+ case AArch64::BI_InterlockedOr16_rel:
+ case AArch64::BI_InterlockedOr_rel:
+ case AArch64::BI_InterlockedOr64_rel:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_rel, E);
+ case AArch64::BI_InterlockedOr8_nf:
+ case AArch64::BI_InterlockedOr16_nf:
+ case AArch64::BI_InterlockedOr_nf:
+ case AArch64::BI_InterlockedOr64_nf:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_nf, E);
+ case AArch64::BI_InterlockedXor8_acq:
+ case AArch64::BI_InterlockedXor16_acq:
+ case AArch64::BI_InterlockedXor_acq:
+ case AArch64::BI_InterlockedXor64_acq:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_acq, E);
+ case AArch64::BI_InterlockedXor8_rel:
+ case AArch64::BI_InterlockedXor16_rel:
+ case AArch64::BI_InterlockedXor_rel:
+ case AArch64::BI_InterlockedXor64_rel:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_rel, E);
+ case AArch64::BI_InterlockedXor8_nf:
+ case AArch64::BI_InterlockedXor16_nf:
+ case AArch64::BI_InterlockedXor_nf:
+ case AArch64::BI_InterlockedXor64_nf:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_nf, E);
+ case AArch64::BI_InterlockedAnd8_acq:
+ case AArch64::BI_InterlockedAnd16_acq:
+ case AArch64::BI_InterlockedAnd_acq:
+ case AArch64::BI_InterlockedAnd64_acq:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_acq, E);
+ case AArch64::BI_InterlockedAnd8_rel:
+ case AArch64::BI_InterlockedAnd16_rel:
+ case AArch64::BI_InterlockedAnd_rel:
+ case AArch64::BI_InterlockedAnd64_rel:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_rel, E);
+ case AArch64::BI_InterlockedAnd8_nf:
+ case AArch64::BI_InterlockedAnd16_nf:
+ case AArch64::BI_InterlockedAnd_nf:
+ case AArch64::BI_InterlockedAnd64_nf:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_nf, E);
+ case AArch64::BI_InterlockedIncrement16_acq:
+ case AArch64::BI_InterlockedIncrement_acq:
+ case AArch64::BI_InterlockedIncrement64_acq:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_acq, E);
+ case AArch64::BI_InterlockedIncrement16_rel:
+ case AArch64::BI_InterlockedIncrement_rel:
+ case AArch64::BI_InterlockedIncrement64_rel:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_rel, E);
+ case AArch64::BI_InterlockedIncrement16_nf:
+ case AArch64::BI_InterlockedIncrement_nf:
+ case AArch64::BI_InterlockedIncrement64_nf:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_nf, E);
+ case AArch64::BI_InterlockedDecrement16_acq:
+ case AArch64::BI_InterlockedDecrement_acq:
+ case AArch64::BI_InterlockedDecrement64_acq:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_acq, E);
+ case AArch64::BI_InterlockedDecrement16_rel:
+ case AArch64::BI_InterlockedDecrement_rel:
+ case AArch64::BI_InterlockedDecrement64_rel:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_rel, E);
+ case AArch64::BI_InterlockedDecrement16_nf:
+ case AArch64::BI_InterlockedDecrement_nf:
+ case AArch64::BI_InterlockedDecrement64_nf:
+ return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_nf, E);
+
+ case AArch64::BI_InterlockedAdd: {
+ Value *Arg0 = EmitScalarExpr(E->getArg(0));
+ Value *Arg1 = EmitScalarExpr(E->getArg(1));
+ AtomicRMWInst *RMWI = Builder.CreateAtomicRMW(
+ AtomicRMWInst::Add, Arg0, Arg1,
+ llvm::AtomicOrdering::SequentiallyConsistent);
+ return Builder.CreateAdd(RMWI, Arg1);
+ }
}
llvm::VectorType *VTy = GetNeonType(this, Type);
@@ -9128,152 +9297,38 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Int = Intrinsic::aarch64_neon_suqadd;
return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vuqadd");
}
- case AArch64::BI_BitScanForward:
- case AArch64::BI_BitScanForward64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanForward, E);
- case AArch64::BI_BitScanReverse:
- case AArch64::BI_BitScanReverse64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanReverse, E);
- case AArch64::BI_InterlockedAnd64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd, E);
- case AArch64::BI_InterlockedExchange64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange, E);
- case AArch64::BI_InterlockedExchangeAdd64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd, E);
- case AArch64::BI_InterlockedExchangeSub64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeSub, E);
- case AArch64::BI_InterlockedOr64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr, E);
- case AArch64::BI_InterlockedXor64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor, E);
- case AArch64::BI_InterlockedDecrement64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement, E);
- case AArch64::BI_InterlockedIncrement64:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement, E);
- case AArch64::BI_InterlockedExchangeAdd8_acq:
- case AArch64::BI_InterlockedExchangeAdd16_acq:
- case AArch64::BI_InterlockedExchangeAdd_acq:
- case AArch64::BI_InterlockedExchangeAdd64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_acq, E);
- case AArch64::BI_InterlockedExchangeAdd8_rel:
- case AArch64::BI_InterlockedExchangeAdd16_rel:
- case AArch64::BI_InterlockedExchangeAdd_rel:
- case AArch64::BI_InterlockedExchangeAdd64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_rel, E);
- case AArch64::BI_InterlockedExchangeAdd8_nf:
- case AArch64::BI_InterlockedExchangeAdd16_nf:
- case AArch64::BI_InterlockedExchangeAdd_nf:
- case AArch64::BI_InterlockedExchangeAdd64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_nf, E);
- case AArch64::BI_InterlockedExchange8_acq:
- case AArch64::BI_InterlockedExchange16_acq:
- case AArch64::BI_InterlockedExchange_acq:
- case AArch64::BI_InterlockedExchange64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_acq, E);
- case AArch64::BI_InterlockedExchange8_rel:
- case AArch64::BI_InterlockedExchange16_rel:
- case AArch64::BI_InterlockedExchange_rel:
- case AArch64::BI_InterlockedExchange64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_rel, E);
- case AArch64::BI_InterlockedExchange8_nf:
- case AArch64::BI_InterlockedExchange16_nf:
- case AArch64::BI_InterlockedExchange_nf:
- case AArch64::BI_InterlockedExchange64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_nf, E);
- case AArch64::BI_InterlockedCompareExchange8_acq:
- case AArch64::BI_InterlockedCompareExchange16_acq:
- case AArch64::BI_InterlockedCompareExchange_acq:
- case AArch64::BI_InterlockedCompareExchange64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_acq, E);
- case AArch64::BI_InterlockedCompareExchange8_rel:
- case AArch64::BI_InterlockedCompareExchange16_rel:
- case AArch64::BI_InterlockedCompareExchange_rel:
- case AArch64::BI_InterlockedCompareExchange64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_rel, E);
- case AArch64::BI_InterlockedCompareExchange8_nf:
- case AArch64::BI_InterlockedCompareExchange16_nf:
- case AArch64::BI_InterlockedCompareExchange_nf:
- case AArch64::BI_InterlockedCompareExchange64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_nf, E);
- case AArch64::BI_InterlockedOr8_acq:
- case AArch64::BI_InterlockedOr16_acq:
- case AArch64::BI_InterlockedOr_acq:
- case AArch64::BI_InterlockedOr64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_acq, E);
- case AArch64::BI_InterlockedOr8_rel:
- case AArch64::BI_InterlockedOr16_rel:
- case AArch64::BI_InterlockedOr_rel:
- case AArch64::BI_InterlockedOr64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_rel, E);
- case AArch64::BI_InterlockedOr8_nf:
- case AArch64::BI_InterlockedOr16_nf:
- case AArch64::BI_InterlockedOr_nf:
- case AArch64::BI_InterlockedOr64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_nf, E);
- case AArch64::BI_InterlockedXor8_acq:
- case AArch64::BI_InterlockedXor16_acq:
- case AArch64::BI_InterlockedXor_acq:
- case AArch64::BI_InterlockedXor64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_acq, E);
- case AArch64::BI_InterlockedXor8_rel:
- case AArch64::BI_InterlockedXor16_rel:
- case AArch64::BI_InterlockedXor_rel:
- case AArch64::BI_InterlockedXor64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_rel, E);
- case AArch64::BI_InterlockedXor8_nf:
- case AArch64::BI_InterlockedXor16_nf:
- case AArch64::BI_InterlockedXor_nf:
- case AArch64::BI_InterlockedXor64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_nf, E);
- case AArch64::BI_InterlockedAnd8_acq:
- case AArch64::BI_InterlockedAnd16_acq:
- case AArch64::BI_InterlockedAnd_acq:
- case AArch64::BI_InterlockedAnd64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_acq, E);
- case AArch64::BI_InterlockedAnd8_rel:
- case AArch64::BI_InterlockedAnd16_rel:
- case AArch64::BI_InterlockedAnd_rel:
- case AArch64::BI_InterlockedAnd64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_rel, E);
- case AArch64::BI_InterlockedAnd8_nf:
- case AArch64::BI_InterlockedAnd16_nf:
- case AArch64::BI_InterlockedAnd_nf:
- case AArch64::BI_InterlockedAnd64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_nf, E);
- case AArch64::BI_InterlockedIncrement16_acq:
- case AArch64::BI_InterlockedIncrement_acq:
- case AArch64::BI_InterlockedIncrement64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_acq, E);
- case AArch64::BI_InterlockedIncrement16_rel:
- case AArch64::BI_InterlockedIncrement_rel:
- case AArch64::BI_InterlockedIncrement64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_rel, E);
- case AArch64::BI_InterlockedIncrement16_nf:
- case AArch64::BI_InterlockedIncrement_nf:
- case AArch64::BI_InterlockedIncrement64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_nf, E);
- case AArch64::BI_InterlockedDecrement16_acq:
- case AArch64::BI_InterlockedDecrement_acq:
- case AArch64::BI_InterlockedDecrement64_acq:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_acq, E);
- case AArch64::BI_InterlockedDecrement16_rel:
- case AArch64::BI_InterlockedDecrement_rel:
- case AArch64::BI_InterlockedDecrement64_rel:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_rel, E);
- case AArch64::BI_InterlockedDecrement16_nf:
- case AArch64::BI_InterlockedDecrement_nf:
- case AArch64::BI_InterlockedDecrement64_nf:
- return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_nf, E);
-
- case AArch64::BI_InterlockedAdd: {
- Value *Arg0 = EmitScalarExpr(E->getArg(0));
- Value *Arg1 = EmitScalarExpr(E->getArg(1));
- AtomicRMWInst *RMWI = Builder.CreateAtomicRMW(
- AtomicRMWInst::Add, Arg0, Arg1,
- llvm::AtomicOrdering::SequentiallyConsistent);
- return Builder.CreateAdd(RMWI, Arg1);
}
+}
+
+Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID,
+ const CallExpr *E) {
+ assert(BuiltinID == BPF::BI__builtin_preserve_field_info &&
+ "unexpected ARM builtin");
+
+ const Expr *Arg = E->getArg(0);
+ bool IsBitField = Arg->IgnoreParens()->getObjectKind() == OK_BitField;
+
+ if (!getDebugInfo()) {
+ CGM.Error(E->getExprLoc(), "using builtin_preserve_field_info() without -g");
+ return IsBitField ? EmitLValue(Arg).getBitFieldPointer()
+ : EmitLValue(Arg).getPointer();
}
+
+ // Enable underlying preserve_*_access_index() generation.
+ bool OldIsInPreservedAIRegion = IsInPreservedAIRegion;
+ IsInPreservedAIRegion = true;
+ Value *FieldAddr = IsBitField ? EmitLValue(Arg).getBitFieldPointer()
+ : EmitLValue(Arg).getPointer();
+ IsInPreservedAIRegion = OldIsInPreservedAIRegion;
+
+ ConstantInt *C = cast<ConstantInt>(EmitScalarExpr(E->getArg(1)));
+ Value *InfoKind = ConstantInt::get(Int64Ty, C->getSExtValue());
+
+ // Built the IR for the preserve_field_info intrinsic.
+ llvm::Function *FnGetFieldInfo = llvm::Intrinsic::getDeclaration(
+ &CGM.getModule(), llvm::Intrinsic::bpf_preserve_field_info,
+ {FieldAddr->getType()});
+ return Builder.CreateCall(FnGetFieldInfo, {FieldAddr, InfoKind});
}
llvm::Value *CodeGenFunction::
@@ -10034,7 +10089,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Value *RW = ConstantInt::get(Int32Ty, (C->getZExtValue() >> 2) & 0x1);
Value *Locality = ConstantInt::get(Int32Ty, C->getZExtValue() & 0x3);
Value *Data = ConstantInt::get(Int32Ty, 1);
- Function *F = CGM.getIntrinsic(Intrinsic::prefetch);
+ Function *F = CGM.getIntrinsic(Intrinsic::prefetch, Address->getType());
return Builder.CreateCall(F, {Address, RW, Locality, Data});
}
case X86::BI_mm_clflush: {
@@ -11169,7 +11224,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
// Unaligned nontemporal store of the scalar value.
StoreInst *SI = Builder.CreateDefaultAlignedStore(Src, BC);
SI->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node);
- SI->setAlignment(1);
+ SI->setAlignment(llvm::Align::None());
return SI;
}
// Rotate is a special case of funnel shift - 1st 2 args are the same.
@@ -12113,7 +12168,8 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
case X86::BI_AddressOfReturnAddress: {
- Function *F = CGM.getIntrinsic(Intrinsic::addressofreturnaddress);
+ Function *F =
+ CGM.getIntrinsic(Intrinsic::addressofreturnaddress, AllocaInt8PtrTy);
return Builder.CreateCall(F);
}
case X86::BI__stosb: {
@@ -13924,6 +13980,15 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_size, ResultType);
return Builder.CreateCall(Callee);
}
+ case WebAssembly::BI__builtin_wasm_tls_align: {
+ llvm::Type *ResultType = ConvertType(E->getType());
+ Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_align, ResultType);
+ return Builder.CreateCall(Callee);
+ }
+ case WebAssembly::BI__builtin_wasm_tls_base: {
+ Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_base);
+ return Builder.CreateCall(Callee);
+ }
case WebAssembly::BI__builtin_wasm_throw: {
Value *Tag = EmitScalarExpr(E->getArg(0));
Value *Obj = EmitScalarExpr(E->getArg(1));
@@ -13954,6 +14019,26 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_atomic_notify);
return Builder.CreateCall(Callee, {Addr, Count});
}
+ case WebAssembly::BI__builtin_wasm_trunc_s_i32_f32:
+ case WebAssembly::BI__builtin_wasm_trunc_s_i32_f64:
+ case WebAssembly::BI__builtin_wasm_trunc_s_i64_f32:
+ case WebAssembly::BI__builtin_wasm_trunc_s_i64_f64: {
+ Value *Src = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ResT = ConvertType(E->getType());
+ Function *Callee =
+ CGM.getIntrinsic(Intrinsic::wasm_trunc_signed, {ResT, Src->getType()});
+ return Builder.CreateCall(Callee, {Src});
+ }
+ case WebAssembly::BI__builtin_wasm_trunc_u_i32_f32:
+ case WebAssembly::BI__builtin_wasm_trunc_u_i32_f64:
+ case WebAssembly::BI__builtin_wasm_trunc_u_i64_f32:
+ case WebAssembly::BI__builtin_wasm_trunc_u_i64_f64: {
+ Value *Src = EmitScalarExpr(E->getArg(0));
+ llvm::Type *ResT = ConvertType(E->getType());
+ Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_trunc_unsigned,
+ {ResT, Src->getType()});
+ return Builder.CreateCall(Callee, {Src});
+ }
case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f32:
case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f64:
case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i64_f32:
@@ -13998,6 +14083,12 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
ConvertType(E->getType()));
return Builder.CreateCall(Callee, {LHS, RHS});
}
+ case WebAssembly::BI__builtin_wasm_swizzle_v8x16: {
+ Value *Src = EmitScalarExpr(E->getArg(0));
+ Value *Indices = EmitScalarExpr(E->getArg(1));
+ Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_swizzle);
+ return Builder.CreateCall(Callee, {Src, Indices});
+ }
case WebAssembly::BI__builtin_wasm_extract_lane_s_i8x16:
case WebAssembly::BI__builtin_wasm_extract_lane_u_i8x16:
case WebAssembly::BI__builtin_wasm_extract_lane_s_i16x8:
@@ -14139,7 +14230,86 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
Function *Callee = CGM.getIntrinsic(Intrinsic::sqrt, Vec->getType());
return Builder.CreateCall(Callee, {Vec});
}
-
+ case WebAssembly::BI__builtin_wasm_qfma_f32x4:
+ case WebAssembly::BI__builtin_wasm_qfms_f32x4:
+ case WebAssembly::BI__builtin_wasm_qfma_f64x2:
+ case WebAssembly::BI__builtin_wasm_qfms_f64x2: {
+ Value *A = EmitScalarExpr(E->getArg(0));
+ Value *B = EmitScalarExpr(E->getArg(1));
+ Value *C = EmitScalarExpr(E->getArg(2));
+ unsigned IntNo;
+ switch (BuiltinID) {
+ case WebAssembly::BI__builtin_wasm_qfma_f32x4:
+ case WebAssembly::BI__builtin_wasm_qfma_f64x2:
+ IntNo = Intrinsic::wasm_qfma;
+ break;
+ case WebAssembly::BI__builtin_wasm_qfms_f32x4:
+ case WebAssembly::BI__builtin_wasm_qfms_f64x2:
+ IntNo = Intrinsic::wasm_qfms;
+ break;
+ default:
+ llvm_unreachable("unexpected builtin ID");
+ }
+ Function *Callee = CGM.getIntrinsic(IntNo, A->getType());
+ return Builder.CreateCall(Callee, {A, B, C});
+ }
+ case WebAssembly::BI__builtin_wasm_narrow_s_i8x16_i16x8:
+ case WebAssembly::BI__builtin_wasm_narrow_u_i8x16_i16x8:
+ case WebAssembly::BI__builtin_wasm_narrow_s_i16x8_i32x4:
+ case WebAssembly::BI__builtin_wasm_narrow_u_i16x8_i32x4: {
+ Value *Low = EmitScalarExpr(E->getArg(0));
+ Value *High = EmitScalarExpr(E->getArg(1));
+ unsigned IntNo;
+ switch (BuiltinID) {
+ case WebAssembly::BI__builtin_wasm_narrow_s_i8x16_i16x8:
+ case WebAssembly::BI__builtin_wasm_narrow_s_i16x8_i32x4:
+ IntNo = Intrinsic::wasm_narrow_signed;
+ break;
+ case WebAssembly::BI__builtin_wasm_narrow_u_i8x16_i16x8:
+ case WebAssembly::BI__builtin_wasm_narrow_u_i16x8_i32x4:
+ IntNo = Intrinsic::wasm_narrow_unsigned;
+ break;
+ default:
+ llvm_unreachable("unexpected builtin ID");
+ }
+ Function *Callee =
+ CGM.getIntrinsic(IntNo, {ConvertType(E->getType()), Low->getType()});
+ return Builder.CreateCall(Callee, {Low, High});
+ }
+ case WebAssembly::BI__builtin_wasm_widen_low_s_i16x8_i8x16:
+ case WebAssembly::BI__builtin_wasm_widen_high_s_i16x8_i8x16:
+ case WebAssembly::BI__builtin_wasm_widen_low_u_i16x8_i8x16:
+ case WebAssembly::BI__builtin_wasm_widen_high_u_i16x8_i8x16:
+ case WebAssembly::BI__builtin_wasm_widen_low_s_i32x4_i16x8:
+ case WebAssembly::BI__builtin_wasm_widen_high_s_i32x4_i16x8:
+ case WebAssembly::BI__builtin_wasm_widen_low_u_i32x4_i16x8:
+ case WebAssembly::BI__builtin_wasm_widen_high_u_i32x4_i16x8: {
+ Value *Vec = EmitScalarExpr(E->getArg(0));
+ unsigned IntNo;
+ switch (BuiltinID) {
+ case WebAssembly::BI__builtin_wasm_widen_low_s_i16x8_i8x16:
+ case WebAssembly::BI__builtin_wasm_widen_low_s_i32x4_i16x8:
+ IntNo = Intrinsic::wasm_widen_low_signed;
+ break;
+ case WebAssembly::BI__builtin_wasm_widen_high_s_i16x8_i8x16:
+ case WebAssembly::BI__builtin_wasm_widen_high_s_i32x4_i16x8:
+ IntNo = Intrinsic::wasm_widen_high_signed;
+ break;
+ case WebAssembly::BI__builtin_wasm_widen_low_u_i16x8_i8x16:
+ case WebAssembly::BI__builtin_wasm_widen_low_u_i32x4_i16x8:
+ IntNo = Intrinsic::wasm_widen_low_unsigned;
+ break;
+ case WebAssembly::BI__builtin_wasm_widen_high_u_i16x8_i8x16:
+ case WebAssembly::BI__builtin_wasm_widen_high_u_i32x4_i16x8:
+ IntNo = Intrinsic::wasm_widen_high_unsigned;
+ break;
+ default:
+ llvm_unreachable("unexpected builtin ID");
+ }
+ Function *Callee =
+ CGM.getIntrinsic(IntNo, {ConvertType(E->getType()), Vec->getType()});
+ return Builder.CreateCall(Callee, Vec);
+ }
default:
return nullptr;
}
diff --git a/lib/CodeGen/CGCUDANV.cpp b/lib/CodeGen/CGCUDANV.cpp
index 4d4038dae9cf..5c5cbaff0252 100644
--- a/lib/CodeGen/CGCUDANV.cpp
+++ b/lib/CodeGen/CGCUDANV.cpp
@@ -93,7 +93,7 @@ private:
GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::None);
}
if (Alignment)
- GV->setAlignment(Alignment);
+ GV->setAlignment(llvm::Align(Alignment));
return llvm::ConstantExpr::getGetElementPtr(ConstStr.getElementType(),
ConstStr.getPointer(), Zeros);
@@ -236,7 +236,8 @@ void CGNVCUDARuntime::emitDeviceStub(CodeGenFunction &CGF,
EmittedKernels.push_back({CGF.CurFn, CGF.CurFuncDecl});
if (CudaFeatureEnabled(CGM.getTarget().getSDKVersion(),
- CudaFeature::CUDA_USES_NEW_LAUNCH))
+ CudaFeature::CUDA_USES_NEW_LAUNCH) ||
+ CGF.getLangOpts().HIPUseNewLaunchAPI)
emitDeviceStubBodyNew(CGF, Args);
else
emitDeviceStubBodyLegacy(CGF, Args);
@@ -264,14 +265,18 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF,
llvm::BasicBlock *EndBlock = CGF.createBasicBlock("setup.end");
- // Lookup cudaLaunchKernel function.
+ // Lookup cudaLaunchKernel/hipLaunchKernel function.
// cudaError_t cudaLaunchKernel(const void *func, dim3 gridDim, dim3 blockDim,
// void **args, size_t sharedMem,
// cudaStream_t stream);
+ // hipError_t hipLaunchKernel(const void *func, dim3 gridDim, dim3 blockDim,
+ // void **args, size_t sharedMem,
+ // hipStream_t stream);
TranslationUnitDecl *TUDecl = CGM.getContext().getTranslationUnitDecl();
DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl);
+ auto LaunchKernelName = addPrefixToName("LaunchKernel");
IdentifierInfo &cudaLaunchKernelII =
- CGM.getContext().Idents.get("cudaLaunchKernel");
+ CGM.getContext().Idents.get(LaunchKernelName);
FunctionDecl *cudaLaunchKernelFD = nullptr;
for (const auto &Result : DC->lookup(&cudaLaunchKernelII)) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Result))
@@ -280,7 +285,7 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF,
if (cudaLaunchKernelFD == nullptr) {
CGM.Error(CGF.CurFuncDecl->getLocation(),
- "Can't find declaration for cudaLaunchKernel()");
+ "Can't find declaration for " + LaunchKernelName);
return;
}
// Create temporary dim3 grid_dim, block_dim.
@@ -301,7 +306,7 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF,
/*ShmemSize=*/ShmemSize.getType(),
/*Stream=*/Stream.getType()},
/*isVarArg=*/false),
- "__cudaPopCallConfiguration");
+ addUnderscoredPrefixToName("PopCallConfiguration"));
CGF.EmitRuntimeCallOrInvoke(cudaPopConfigFn,
{GridDim.getPointer(), BlockDim.getPointer(),
@@ -329,7 +334,7 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF,
const CGFunctionInfo &FI =
CGM.getTypes().arrangeFunctionDeclaration(cudaLaunchKernelFD);
llvm::FunctionCallee cudaLaunchKernelFn =
- CGM.CreateRuntimeFunction(FTy, "cudaLaunchKernel");
+ CGM.CreateRuntimeFunction(FTy, LaunchKernelName);
CGF.EmitCall(FI, CGCallee::forDirect(cudaLaunchKernelFn), ReturnValueSlot(),
LaunchKernelArgs);
CGF.EmitBranch(EndBlock);
@@ -623,7 +628,7 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
Linkage,
/*Initializer=*/llvm::ConstantPointerNull::get(VoidPtrPtrTy),
"__hip_gpubin_handle");
- GpuBinaryHandle->setAlignment(CGM.getPointerAlign().getQuantity());
+ GpuBinaryHandle->setAlignment(CGM.getPointerAlign().getAsAlign());
// Prevent the weak symbol in different shared libraries being merged.
if (Linkage != llvm::GlobalValue::InternalLinkage)
GpuBinaryHandle->setVisibility(llvm::GlobalValue::HiddenVisibility);
@@ -664,7 +669,7 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() {
GpuBinaryHandle = new llvm::GlobalVariable(
TheModule, VoidPtrPtrTy, false, llvm::GlobalValue::InternalLinkage,
llvm::ConstantPointerNull::get(VoidPtrPtrTy), "__cuda_gpubin_handle");
- GpuBinaryHandle->setAlignment(CGM.getPointerAlign().getQuantity());
+ GpuBinaryHandle->setAlignment(CGM.getPointerAlign().getAsAlign());
CtorBuilder.CreateAlignedStore(RegisterFatbinCall, GpuBinaryHandle,
CGM.getPointerAlign());
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 6d903a0d09e2..7e5fe0fd6b1d 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -80,7 +80,7 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
// Skip base classes with trivial destructors.
const auto *Base =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
if (Base->hasTrivialDestructor()) continue;
// If we've already found a base class with a non-trivial
@@ -104,8 +104,8 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
// Give up if the calling conventions don't match. We could update the call,
// but it is probably not worth it.
const CXXDestructorDecl *BaseD = UniqueBase->getDestructor();
- if (BaseD->getType()->getAs<FunctionType>()->getCallConv() !=
- D->getType()->getAs<FunctionType>()->getCallConv())
+ if (BaseD->getType()->castAs<FunctionType>()->getCallConv() !=
+ D->getType()->castAs<FunctionType>()->getCallConv())
return true;
GlobalDecl AliasDecl(D, Dtor_Base);
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index 041c0f8959fd..23dae2b61d04 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -46,8 +46,8 @@ CGCallee CGCXXABI::EmitLoadOfMemberFunctionPointer(
ThisPtrForCall = This.getPointer();
const FunctionProtoType *FPT =
MPT->getPointeeType()->getAs<FunctionProtoType>();
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
+ const auto *RD =
+ cast<CXXRecordDecl>(MPT->getClass()->castAs<RecordType>()->getDecl());
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(
CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr));
llvm::Constant *FnPtr = llvm::Constant::getNullValue(FTy->getPointerTo());
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index 3a9c3b347439..bff49be7a3c4 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -577,7 +577,7 @@ public:
// Determine if references to thread_local global variables can be made
// directly or require access through a thread wrapper function.
- virtual bool usesThreadWrapperFunction() const = 0;
+ virtual bool usesThreadWrapperFunction(const VarDecl *VD) const = 0;
/// Emit a reference to a non-local thread_local variable (including
/// triggering the initialization of all thread_local variables in its
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index cf8024550eee..b74f6f942426 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -903,7 +903,7 @@ struct NoExpansion : TypeExpansion {
static std::unique_ptr<TypeExpansion>
getTypeExpansion(QualType Ty, const ASTContext &Context) {
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) {
- return llvm::make_unique<ConstantArrayExpansion>(
+ return std::make_unique<ConstantArrayExpansion>(
AT->getElementType(), AT->getSize().getZExtValue());
}
if (const RecordType *RT = Ty->getAs<RecordType>()) {
@@ -947,13 +947,13 @@ getTypeExpansion(QualType Ty, const ASTContext &Context) {
Fields.push_back(FD);
}
}
- return llvm::make_unique<RecordExpansion>(std::move(Bases),
+ return std::make_unique<RecordExpansion>(std::move(Bases),
std::move(Fields));
}
if (const ComplexType *CT = Ty->getAs<ComplexType>()) {
- return llvm::make_unique<ComplexExpansion>(CT->getElementType());
+ return std::make_unique<ComplexExpansion>(CT->getElementType());
}
- return llvm::make_unique<NoExpansion>();
+ return std::make_unique<NoExpansion>();
}
static int getExpansionSize(QualType Ty, const ASTContext &Context) {
@@ -1713,16 +1713,19 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
if (!CodeGenOpts.TrapFuncName.empty())
FuncAttrs.addAttribute("trap-func-name", CodeGenOpts.TrapFuncName);
} else {
- // Attributes that should go on the function, but not the call site.
- if (!CodeGenOpts.DisableFPElim) {
- FuncAttrs.addAttribute("no-frame-pointer-elim", "false");
- } else if (CodeGenOpts.OmitLeafFramePointer) {
- FuncAttrs.addAttribute("no-frame-pointer-elim", "false");
- FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf");
- } else {
- FuncAttrs.addAttribute("no-frame-pointer-elim", "true");
- FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf");
+ StringRef FpKind;
+ switch (CodeGenOpts.getFramePointer()) {
+ case CodeGenOptions::FramePointerKind::None:
+ FpKind = "none";
+ break;
+ case CodeGenOptions::FramePointerKind::NonLeaf:
+ FpKind = "non-leaf";
+ break;
+ case CodeGenOptions::FramePointerKind::All:
+ FpKind = "all";
+ break;
}
+ FuncAttrs.addAttribute("frame-pointer", FpKind);
FuncAttrs.addAttribute("less-precise-fpmad",
llvm::toStringRef(CodeGenOpts.LessPreciseFPMAD));
@@ -2123,8 +2126,8 @@ void CodeGenModule::ConstructAttributeList(
if (!PTy->isIncompleteType() && PTy->isConstantSizeType()) {
auto info = getContext().getTypeInfoInChars(PTy);
Attrs.addDereferenceableAttr(info.first.getQuantity());
- Attrs.addAttribute(llvm::Attribute::getWithAlignment(getLLVMContext(),
- info.second.getQuantity()));
+ Attrs.addAttribute(llvm::Attribute::getWithAlignment(
+ getLLVMContext(), info.second.getAsAlign()));
}
break;
}
@@ -3089,8 +3092,8 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
// Deactivate the cleanup for the callee-destructed param that was pushed.
if (hasAggregateEvaluationKind(type) && !CurFuncIsThunk &&
- type->getAs<RecordType>()->getDecl()->isParamDestroyedInCallee() &&
- type.isDestructedType()) {
+ type->castAs<RecordType>()->getDecl()->isParamDestroyedInCallee() &&
+ param->needsDestruction(getContext())) {
EHScopeStack::stable_iterator cleanup =
CalleeDestructedParamCleanups.lookup(cast<ParmVarDecl>(param));
assert(cleanup.isValid() &&
@@ -3574,7 +3577,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
// However, we still have to push an EH-only cleanup in case we unwind before
// we make it to the call.
if (HasAggregateEvalKind &&
- type->getAs<RecordType>()->getDecl()->isParamDestroyedInCallee()) {
+ type->castAs<RecordType>()->getDecl()->isParamDestroyedInCallee()) {
// If we're using inalloca, use the argument memory. Otherwise, use a
// temporary.
AggValueSlot Slot;
@@ -3838,7 +3841,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
AI = CreateTempAlloca(ArgStruct, "argmem");
}
auto Align = CallInfo.getArgStructAlignment();
- AI->setAlignment(Align.getQuantity());
+ AI->setAlignment(Align.getAsAlign());
AI->setUsedWithInAlloca(true);
assert(AI->isUsedWithInAlloca() && !AI->isStaticAlloca());
ArgMemory = Address(AI, Align);
@@ -3875,6 +3878,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Address swiftErrorTemp = Address::invalid();
Address swiftErrorArg = Address::invalid();
+ // When passing arguments using temporary allocas, we need to add the
+ // appropriate lifetime markers. This vector keeps track of all the lifetime
+ // markers that need to be ended right after the call.
+ SmallVector<CallLifetimeEnd, 2> CallLifetimeEndAfterCall;
+
// Translate all of the arguments as necessary to match the IR lowering.
assert(CallInfo.arg_size() == CallArgs.size() &&
"Mismatch between function signature & arguments.");
@@ -3991,6 +3999,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Address AI = CreateMemTempWithoutCast(
I->Ty, ArgInfo.getIndirectAlign(), "byval-temp");
IRCallArgs[FirstIRArg] = AI.getPointer();
+
+ // Emit lifetime markers for the temporary alloca.
+ uint64_t ByvalTempElementSize =
+ CGM.getDataLayout().getTypeAllocSize(AI.getElementType());
+ llvm::Value *LifetimeSize =
+ EmitLifetimeStart(ByvalTempElementSize, AI.getPointer());
+
+ // Add cleanup code to emit the end lifetime marker after the call.
+ if (LifetimeSize) // In case we disabled lifetime markers.
+ CallLifetimeEndAfterCall.emplace_back(AI, LifetimeSize);
+
+ // Generate the copy.
I->copyInto(*this, AI);
} else {
// Skip the extra memcpy call.
@@ -4129,11 +4149,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
auto scalarAlign = CGM.getDataLayout().getPrefTypeAlignment(scalarType);
// Materialize to a temporary.
- addr = CreateTempAlloca(RV.getScalarVal()->getType(),
- CharUnits::fromQuantity(std::max(
- layout->getAlignment(), scalarAlign)),
- "tmp",
- /*ArraySize=*/nullptr, &AllocaAddr);
+ addr = CreateTempAlloca(
+ RV.getScalarVal()->getType(),
+ CharUnits::fromQuantity(std::max(
+ (unsigned)layout->getAlignment().value(), scalarAlign)),
+ "tmp",
+ /*ArraySize=*/nullptr, &AllocaAddr);
tempSize = EmitLifetimeStart(scalarSize, AllocaAddr.getPointer());
Builder.CreateStore(RV.getScalarVal(), addr);
@@ -4273,8 +4294,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// Update the largest vector width if any arguments have vector types.
for (unsigned i = 0; i < IRCallArgs.size(); ++i) {
if (auto *VT = dyn_cast<llvm::VectorType>(IRCallArgs[i]->getType()))
- LargestVectorWidth = std::max(LargestVectorWidth,
- VT->getPrimitiveSizeInBits());
+ LargestVectorWidth = std::max((uint64_t)LargestVectorWidth,
+ VT->getPrimitiveSizeInBits().getFixedSize());
}
// Compute the calling convention and attributes.
@@ -4357,8 +4378,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// Update largest vector width from the return type.
if (auto *VT = dyn_cast<llvm::VectorType>(CI->getType()))
- LargestVectorWidth = std::max(LargestVectorWidth,
- VT->getPrimitiveSizeInBits());
+ LargestVectorWidth = std::max((uint64_t)LargestVectorWidth,
+ VT->getPrimitiveSizeInBits().getFixedSize());
// Insert instrumentation or attach profile metadata at indirect call sites.
// For more details, see the comment before the definition of
@@ -4548,7 +4569,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::Value *Alignment = EmitScalarExpr(AA->getAlignment());
llvm::ConstantInt *AlignmentCI = cast<llvm::ConstantInt>(Alignment);
EmitAlignmentAssumption(Ret.getScalarVal(), RetTy, Loc, AA->getLocation(),
- AlignmentCI->getZExtValue(), OffsetValue);
+ AlignmentCI, OffsetValue);
} else if (const auto *AA = TargetDecl->getAttr<AllocAlignAttr>()) {
llvm::Value *AlignmentVal = CallArgs[AA->getParamIndex().getLLVMIndex()]
.getRValue(*this)
@@ -4558,6 +4579,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
}
+ // Explicitly call CallLifetimeEnd::Emit just to re-use the code even though
+ // we can't use the full cleanup mechanism.
+ for (CallLifetimeEnd &LifetimeEnd : CallLifetimeEndAfterCall)
+ LifetimeEnd.Emit(*this, /*Flags=*/{});
+
return Ret;
}
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index c8bb63c5c4b1..04ef912b18bd 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -161,8 +161,8 @@ CharUnits CodeGenModule::computeNonVirtualBaseClassOffset(
// Get the layout.
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ const auto *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->castAs<RecordType>()->getDecl());
// Add the offset.
Offset += Layout.getBaseClassOffset(BaseDecl);
@@ -246,7 +246,8 @@ ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, Address addr,
// Apply the base offset.
llvm::Value *ptr = addr.getPointer();
- ptr = CGF.Builder.CreateBitCast(ptr, CGF.Int8PtrTy);
+ unsigned AddrSpace = ptr->getType()->getPointerAddressSpace();
+ ptr = CGF.Builder.CreateBitCast(ptr, CGF.Int8Ty->getPointerTo(AddrSpace));
ptr = CGF.Builder.CreateInBoundsGEP(ptr, baseOffset, "add.ptr");
// If we have a virtual component, the alignment of the result will
@@ -279,8 +280,8 @@ Address CodeGenFunction::GetAddressOfBaseClass(
// *start* with a step down to the correct virtual base subobject,
// and hence will not require any further steps.
if ((*Start)->isVirtual()) {
- VBase =
- cast<CXXRecordDecl>((*Start)->getType()->getAs<RecordType>()->getDecl());
+ VBase = cast<CXXRecordDecl>(
+ (*Start)->getType()->castAs<RecordType>()->getDecl());
++Start;
}
@@ -381,7 +382,9 @@ CodeGenFunction::GetAddressOfDerivedClass(Address BaseAddr,
QualType DerivedTy =
getContext().getCanonicalType(getContext().getTagDeclType(Derived));
- llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
+ unsigned AddrSpace =
+ BaseAddr.getPointer()->getType()->getPointerAddressSpace();
+ llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo(AddrSpace);
llvm::Value *NonVirtualOffset =
CGM.GetNonVirtualBaseClassOffset(Derived, PathBegin, PathEnd);
@@ -536,8 +539,8 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
Address ThisPtr = CGF.LoadCXXThisAddress();
const Type *BaseType = BaseInit->getBaseClass();
- CXXRecordDecl *BaseClassDecl =
- cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
+ const auto *BaseClassDecl =
+ cast<CXXRecordDecl>(BaseType->castAs<RecordType>()->getDecl());
bool isBaseVirtual = BaseInit->isBaseVirtual();
@@ -739,7 +742,7 @@ bool CodeGenFunction::IsConstructorDelegationValid(
// We also disable the optimization for variadic functions because
// it's impossible to "re-pass" varargs.
- if (Ctor->getType()->getAs<FunctionProtoType>()->isVariadic())
+ if (Ctor->getType()->castAs<FunctionProtoType>()->isVariadic())
return false;
// FIXME: Decide if we can do a delegation of a delegating constructor.
@@ -1245,7 +1248,7 @@ namespace {
static bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit) {
const Type *BaseType = BaseInit->getBaseClass();
const auto *BaseClassDecl =
- cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(BaseType->castAs<RecordType>()->getDecl());
return BaseClassDecl->isDynamicClass();
}
@@ -1814,8 +1817,8 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
// We push them in the forward order so that they'll be popped in
// the reverse order.
for (const auto &Base : ClassDecl->vbases()) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+ auto *BaseClassDecl =
+ cast<CXXRecordDecl>(Base.getType()->castAs<RecordType>()->getDecl());
// Ignore trivial destructors.
if (BaseClassDecl->hasTrivialDestructor())
@@ -2083,7 +2086,7 @@ static bool canEmitDelegateCallArgs(CodeGenFunction &CGF,
if (CGF.getTarget().getCXXABI().areArgsDestroyedLeftToRightInCallee()) {
// If the parameters are callee-cleanup, it's not safe to forward.
for (auto *P : Ctor->parameters())
- if (P->getType().isDestructedType())
+ if (P->needsDestruction(CGF.getContext()))
return false;
// Likewise if they're inalloca.
@@ -2530,8 +2533,8 @@ void CodeGenFunction::getVTablePointers(BaseSubobject Base,
// Traverse bases.
for (const auto &I : RD->bases()) {
- CXXRecordDecl *BaseDecl
- = cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ auto *BaseDecl =
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
// Ignore classes without a vtable.
if (!BaseDecl->isDynamicClass())
@@ -2784,11 +2787,16 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
bool CodeGenFunction::ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD) {
if (!CGM.getCodeGenOpts().WholeProgramVTables ||
- !SanOpts.has(SanitizerKind::CFIVCall) ||
- !CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIVCall) ||
!CGM.HasHiddenLTOVisibility(RD))
return false;
+ if (CGM.getCodeGenOpts().VirtualFunctionElimination)
+ return true;
+
+ if (!SanOpts.has(SanitizerKind::CFIVCall) ||
+ !CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIVCall))
+ return false;
+
std::string TypeName = RD->getQualifiedNameAsString();
return !getContext().getSanitizerBlacklist().isBlacklistedType(
SanitizerKind::CFIVCall, TypeName);
@@ -2811,8 +2819,13 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
TypeId});
llvm::Value *CheckResult = Builder.CreateExtractValue(CheckedLoad, 1);
- EmitCheck(std::make_pair(CheckResult, SanitizerKind::CFIVCall),
- SanitizerHandler::CFICheckFail, nullptr, nullptr);
+ std::string TypeName = RD->getQualifiedNameAsString();
+ if (SanOpts.has(SanitizerKind::CFIVCall) &&
+ !getContext().getSanitizerBlacklist().isBlacklistedType(
+ SanitizerKind::CFIVCall, TypeName)) {
+ EmitCheck(std::make_pair(CheckResult, SanitizerKind::CFIVCall),
+ SanitizerHandler::CFICheckFail, {}, {});
+ }
return Builder.CreateBitCast(
Builder.CreateExtractValue(CheckedLoad, 0),
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index 5594f3030229..c117dd5c25c1 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -304,13 +304,13 @@ void EHScopeStack::Cleanup::anchor() {}
static void createStoreInstBefore(llvm::Value *value, Address addr,
llvm::Instruction *beforeInst) {
auto store = new llvm::StoreInst(value, addr.getPointer(), beforeInst);
- store->setAlignment(addr.getAlignment().getQuantity());
+ store->setAlignment(addr.getAlignment().getAsAlign());
}
static llvm::LoadInst *createLoadInstBefore(Address addr, const Twine &name,
llvm::Instruction *beforeInst) {
auto load = new llvm::LoadInst(addr.getPointer(), name, beforeInst);
- load->setAlignment(addr.getAlignment().getQuantity());
+ load->setAlignment(addr.getAlignment().getAsAlign());
return load;
}
@@ -740,14 +740,15 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
// here. Unfortunately, if you ask for a SmallVector<char>, the
// alignment isn't sufficient.
auto *CleanupSource = reinterpret_cast<char *>(Scope.getCleanupBuffer());
- llvm::AlignedCharArray<EHScopeStack::ScopeStackAlignment, 8 * sizeof(void *)> CleanupBufferStack;
+ alignas(EHScopeStack::ScopeStackAlignment) char
+ CleanupBufferStack[8 * sizeof(void *)];
std::unique_ptr<char[]> CleanupBufferHeap;
size_t CleanupSize = Scope.getCleanupSize();
EHScopeStack::Cleanup *Fn;
if (CleanupSize <= sizeof(CleanupBufferStack)) {
- memcpy(CleanupBufferStack.buffer, CleanupSource, CleanupSize);
- Fn = reinterpret_cast<EHScopeStack::Cleanup *>(CleanupBufferStack.buffer);
+ memcpy(CleanupBufferStack, CleanupSource, CleanupSize);
+ Fn = reinterpret_cast<EHScopeStack::Cleanup *>(CleanupBufferStack);
} else {
CleanupBufferHeap.reset(new char[CleanupSize]);
memcpy(CleanupBufferHeap.get(), CleanupSource, CleanupSize);
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index f6ee7ee26d4b..7c63743f3b43 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -314,7 +314,9 @@ StringRef CGDebugInfo::getClassName(const RecordDecl *RD) {
if (isa<ClassTemplateSpecializationDecl>(RD)) {
SmallString<128> Name;
llvm::raw_svector_ostream OS(Name);
- RD->getNameForDiagnostic(OS, getPrintingPolicy(),
+ PrintingPolicy PP = getPrintingPolicy();
+ PP.PrintCanonicalTypes = true;
+ RD->getNameForDiagnostic(OS, PP,
/*Qualified*/ false);
// Copy this name on the side and use its reference.
@@ -537,11 +539,11 @@ void CGDebugInfo::CreateCompileUnit() {
// file to determine the real absolute path for the file.
std::string MainFileDir;
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
- MainFileDir = remapDIPath(MainFile->getDir()->getName());
- if (MainFileDir != ".") {
+ MainFileDir = MainFile->getDir()->getName();
+ if (!llvm::sys::path::is_absolute(MainFileName)) {
llvm::SmallString<1024> MainFileDirSS(MainFileDir);
llvm::sys::path::append(MainFileDirSS, MainFileName);
- MainFileName = MainFileDirSS.str();
+ MainFileName = llvm::sys::path::remove_leading_dotslash(MainFileDirSS);
}
// If the main file name provided is identical to the input file name, and
// if the input file is a preprocessed source, use the module name for
@@ -561,6 +563,10 @@ void CGDebugInfo::CreateCompileUnit() {
if (LO.CPlusPlus) {
if (LO.ObjC)
LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus;
+ else if (LO.CPlusPlus14)
+ LangTag = llvm::dwarf::DW_LANG_C_plus_plus_14;
+ else if (LO.CPlusPlus11)
+ LangTag = llvm::dwarf::DW_LANG_C_plus_plus_11;
else
LangTag = llvm::dwarf::DW_LANG_C_plus_plus;
} else if (LO.ObjC) {
@@ -697,6 +703,22 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) {
case BuiltinType::Id: \
return getOrCreateStructPtrType("opencl_" #ExtType, Id##Ty);
#include "clang/Basic/OpenCLExtensionTypes.def"
+ // TODO: real support for SVE types requires more infrastructure
+ // to be added first. The types have a variable length and are
+ // represented in debug info as types whose length depends on a
+ // target-specific pseudo register.
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
+ {
+ unsigned DiagID = CGM.getDiags().getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "cannot yet generate debug info for SVE type '%0'");
+ auto Name = BT->getName(CGM.getContext().getPrintingPolicy());
+ CGM.getDiags().Report(DiagID) << Name;
+ // Return something safe.
+ return CreateType(cast<const BuiltinType>(CGM.getContext().IntTy));
+ }
case BuiltinType::UChar:
case BuiltinType::Char_U:
@@ -862,6 +884,8 @@ llvm::DIType *CGDebugInfo::CreateType(const PointerType *Ty,
static bool hasCXXMangling(const TagDecl *TD, llvm::DICompileUnit *TheCU) {
switch (TheCU->getSourceLanguage()) {
case llvm::dwarf::DW_LANG_C_plus_plus:
+ case llvm::dwarf::DW_LANG_C_plus_plus_11:
+ case llvm::dwarf::DW_LANG_C_plus_plus_14:
return true;
case llvm::dwarf::DW_LANG_ObjC_plus_plus:
return isa<CXXRecordDecl>(TD) || isa<EnumDecl>(TD);
@@ -1583,6 +1607,8 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
ContainingType = RecordTy;
}
+ if (Method->isNoReturn())
+ Flags |= llvm::DINode::FlagNoReturn;
if (Method->isStatic())
Flags |= llvm::DINode::FlagStaticMember;
if (Method->isImplicit())
@@ -1637,7 +1663,7 @@ void CGDebugInfo::CollectCXXMemberFunctions(
if (!Method || Method->isImplicit() || Method->hasAttr<NoDebugAttr>())
continue;
- if (Method->getType()->getAs<FunctionProtoType>()->getContainedAutoType())
+ if (Method->getType()->castAs<FunctionProtoType>()->getContainedAutoType())
continue;
// Reuse the existing member function declaration if it exists.
@@ -1677,7 +1703,7 @@ void CGDebugInfo::CollectCXXBasesAux(
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
for (const auto &BI : Bases) {
const auto *Base =
- cast<CXXRecordDecl>(BI.getType()->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(BI.getType()->castAs<RecordType>()->getDecl());
if (!SeenTypes.insert(Base).second)
continue;
auto *BaseTy = getOrCreateType(BI.getType(), Unit);
@@ -1769,6 +1795,7 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList,
CGM.getContext().toCharUnitsFromBits((int64_t)fieldOffset);
V = CGM.getCXXABI().EmitMemberDataPointer(MPT, chars);
}
+ assert(V && "Failed to find template parameter pointer");
V = V->stripPointerCasts();
}
TemplateParams.push_back(DBuilder.createTemplateValueParameter(
@@ -2695,6 +2722,8 @@ llvm::DIType *CGDebugInfo::CreateType(const MemberPointerType *Ty,
break;
case MSInheritanceAttr::Keyword_unspecified_inheritance:
break;
+ case MSInheritanceAttr::SpellingNotCalculated:
+ llvm_unreachable("Spelling not yet calculated");
}
}
}
@@ -2978,7 +3007,7 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
#define ABSTRACT_TYPE(Class, Base)
#define NON_CANONICAL_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("Dependent types cannot show up in debug information");
case Type::ExtVector:
@@ -3105,7 +3134,8 @@ llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
SmallString<256> Identifier = getTypeIdentifier(Ty, CGM, TheCU);
- // Explicitly record the calling convention for C++ records.
+ // Explicitly record the calling convention and export symbols for C++
+ // records.
auto Flags = llvm::DINode::FlagZero;
if (auto CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
if (CGM.getCXXABI().getRecordArgABI(CXXRD) == CGCXXABI::RAA_Indirect)
@@ -3116,6 +3146,10 @@ llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
// Record if a C++ record is non-trivial type.
if (!CXXRD->isTrivial())
Flags |= llvm::DINode::FlagNonTrivial;
+
+ // Record exports it symbols to the containing structure.
+ if (CXXRD->isAnonymousStructOrUnion())
+ Flags |= llvm::DINode::FlagExportSymbols;
}
llvm::DICompositeType *RealDecl = DBuilder.createReplaceableCompositeType(
@@ -3247,8 +3281,8 @@ void CGDebugInfo::collectVarDeclProps(const VarDecl *VD, llvm::DIFile *&Unit,
llvm::APInt ConstVal(32, 1);
QualType ET = CGM.getContext().getAsArrayType(T)->getElementType();
- T = CGM.getContext().getConstantArrayType(ET, ConstVal, ArrayType::Normal,
- 0);
+ T = CGM.getContext().getConstantArrayType(ET, ConstVal, nullptr,
+ ArrayType::Normal, 0);
}
Name = VD->getName();
@@ -3298,13 +3332,13 @@ llvm::DISubprogram *CGDebugInfo::getFunctionFwdDeclOrStub(GlobalDecl GD,
unsigned Line = getLineNumber(Loc);
collectFunctionDeclProps(GD, Unit, Name, LinkageName, DContext, TParamsArray,
Flags);
- auto *FD = dyn_cast<FunctionDecl>(GD.getDecl());
+ auto *FD = cast<FunctionDecl>(GD.getDecl());
// Build function type.
SmallVector<QualType, 16> ArgTypes;
- if (FD)
- for (const ParmVarDecl *Parm : FD->parameters())
- ArgTypes.push_back(Parm->getType());
+ for (const ParmVarDecl *Parm : FD->parameters())
+ ArgTypes.push_back(Parm->getType());
+
CallingConv CC = FD->getType()->castAs<FunctionType>()->getCallConv();
QualType FnType = CGM.getContext().getFunctionType(
FD->getReturnType(), ArgTypes, FunctionProtoType::ExtProtoInfo(CC));
@@ -3677,8 +3711,7 @@ void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke,
const FunctionDecl *CalleeDecl) {
auto &CGOpts = CGM.getCodeGenOpts();
if (!CGOpts.EnableDebugEntryValues || !CGM.getLangOpts().Optimize ||
- !CallOrInvoke ||
- CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo)
+ !CallOrInvoke)
return;
auto *Func = CallOrInvoke->getCalledFunction();
@@ -3844,8 +3877,8 @@ CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
if (NumPaddingBytes.isPositive()) {
llvm::APInt pad(32, NumPaddingBytes.getQuantity());
- FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy,
- pad, ArrayType::Normal, 0);
+ FType = CGM.getContext().getConstantArrayType(
+ CGM.getContext().CharTy, pad, nullptr, ArrayType::Normal, 0);
EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset));
}
}
@@ -4417,19 +4450,27 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) {
StringRef Name = VD->getName();
llvm::DIType *Ty = getOrCreateType(VD->getType(), Unit);
- // Do not use global variables for enums, unless in CodeView.
if (const auto *ECD = dyn_cast<EnumConstantDecl>(VD)) {
const auto *ED = cast<EnumDecl>(ECD->getDeclContext());
assert(isa<EnumType>(ED->getTypeForDecl()) && "Enum without EnumType?");
- (void)ED;
-
- // If CodeView, emit enums as global variables, unless they are defined
- // inside a class. We do this because MSVC doesn't emit S_CONSTANTs for
- // enums in classes, and because it is difficult to attach this scope
- // information to the global variable.
- if (!CGM.getCodeGenOpts().EmitCodeView ||
- isa<RecordDecl>(ED->getDeclContext()))
+
+ if (CGM.getCodeGenOpts().EmitCodeView) {
+ // If CodeView, emit enums as global variables, unless they are defined
+ // inside a class. We do this because MSVC doesn't emit S_CONSTANTs for
+ // enums in classes, and because it is difficult to attach this scope
+ // information to the global variable.
+ if (isa<RecordDecl>(ED->getDeclContext()))
+ return;
+ } else {
+ // If not CodeView, emit DW_TAG_enumeration_type if necessary. For
+ // example: for "enum { ZERO };", a DW_TAG_enumeration_type is created the
+ // first time `ZERO` is referenced in a function.
+ llvm::DIType *EDTy =
+ getOrCreateType(QualType(ED->getTypeForDecl(), 0), Unit);
+ assert (EDTy->getTag() == llvm::dwarf::DW_TAG_enumeration_type);
+ (void)EDTy;
return;
+ }
}
llvm::DIScope *DContext = nullptr;
@@ -4524,7 +4565,7 @@ void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) {
// return type in the definition)
if (const auto *FD = dyn_cast<FunctionDecl>(USD.getUnderlyingDecl()))
if (const auto *AT =
- FD->getType()->getAs<FunctionProtoType>()->getContainedAutoType())
+ FD->getType()->castAs<FunctionProtoType>()->getContainedAutoType())
if (AT->getDeducedType().isNull())
return;
if (llvm::DINode *Target =
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 6ad43cefc4d2..563841c068f6 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -250,7 +250,7 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
llvm::GlobalVariable *GV = new llvm::GlobalVariable(
getModule(), LTy, Ty.isConstant(getContext()), Linkage, Init, Name,
nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS);
- GV->setAlignment(getContext().getDeclAlign(&D).getQuantity());
+ GV->setAlignment(getContext().getDeclAlign(&D).getAsAlign());
if (supportsCOMDAT() && GV->isWeakForLinker())
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
@@ -305,14 +305,6 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl(
return Addr;
}
-/// 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
@@ -372,7 +364,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
emitter.finalize(GV);
- if (hasNontrivialDestruction(D.getType()) && HaveInsertPoint()) {
+ if (D.needsDestruction(getContext()) && HaveInsertPoint()) {
// We have a constant initializer, but a nontrivial destructor. We still
// need to perform a guarded "initialization" in order to register the
// destructor.
@@ -416,7 +408,7 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
if (D.getInit() && !isCudaSharedVar)
var = AddInitializerToStaticVarDecl(D, var);
- var->setAlignment(alignment.getQuantity());
+ var->setAlignment(alignment.getAsAlign());
if (D.hasAttr<AnnotateAttr>())
CGM.AddGlobalAnnotations(&D, var);
@@ -427,6 +419,8 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
var->addAttribute("data-section", SA->getName());
if (auto *SA = D.getAttr<PragmaClangRodataSectionAttr>())
var->addAttribute("rodata-section", SA->getName());
+ if (auto *SA = D.getAttr<PragmaClangRelroSectionAttr>())
+ var->addAttribute("relro-section", SA->getName());
if (const SectionAttr *SA = D.getAttr<SectionAttr>())
var->setSection(SA->getName());
@@ -1120,11 +1114,11 @@ Address CodeGenModule::createUnnamedGlobalFrom(const VarDecl &D,
llvm::GlobalVariable *GV = new llvm::GlobalVariable(
getModule(), Ty, isConstant, llvm::GlobalValue::PrivateLinkage,
Constant, Name, InsertBefore, llvm::GlobalValue::NotThreadLocal, AS);
- GV->setAlignment(Align.getQuantity());
+ GV->setAlignment(Align.getAsAlign());
GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
CacheEntry = GV;
} else if (CacheEntry->getAlignment() < Align.getQuantity()) {
- CacheEntry->setAlignment(Align.getQuantity());
+ CacheEntry->setAlignment(Align.getAsAlign());
}
return Address(CacheEntry, Align);
@@ -1994,7 +1988,7 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
const VarDecl &D = *emission.Variable;
// Check the type for a cleanup.
- if (QualType::DestructionKind dtorKind = D.getType().isDestructedType())
+ if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext()))
emitAutoVarTypeCleanup(emission, dtorKind);
// In GC mode, honor objc_precise_lifetime.
@@ -2403,8 +2397,9 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg,
// Don't push a cleanup in a thunk for a method that will also emit a
// cleanup.
if (hasAggregateEvaluationKind(Ty) && !CurFuncIsThunk &&
- Ty->getAs<RecordType>()->getDecl()->isParamDestroyedInCallee()) {
- if (QualType::DestructionKind DtorKind = Ty.isDestructedType()) {
+ Ty->castAs<RecordType>()->getDecl()->isParamDestroyedInCallee()) {
+ if (QualType::DestructionKind DtorKind =
+ D.needsDestruction(getContext())) {
assert((DtorKind == QualType::DK_cxx_destructor ||
DtorKind == QualType::DK_nontrivial_c_struct) &&
"unexpected destructor type");
@@ -2496,10 +2491,11 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg,
setAddrOfLocalVar(&D, DeclPtr);
- // Emit debug info for param declaration.
+ // Emit debug info for param declarations in non-thunk functions.
if (CGDebugInfo *DI = getDebugInfo()) {
if (CGM.getCodeGenOpts().getDebugInfo() >=
- codegenoptions::LimitedDebugInfo) {
+ codegenoptions::LimitedDebugInfo &&
+ !CurFuncIsThunk) {
DI->EmitDeclareOfArgVariable(&D, DeclPtr.getPointer(), ArgNo, Builder);
}
}
@@ -2529,10 +2525,11 @@ void CodeGenModule::EmitOMPDeclareReduction(const OMPDeclareReductionDecl *D,
}
void CodeGenModule::EmitOMPDeclareMapper(const OMPDeclareMapperDecl *D,
- CodeGenFunction *CGF) {
- if (!LangOpts.OpenMP || (!LangOpts.EmitAllDecls && !D->isUsed()))
+ CodeGenFunction *CGF) {
+ if (!LangOpts.OpenMP || LangOpts.OpenMPSimd ||
+ (!LangOpts.EmitAllDecls && !D->isUsed()))
return;
- // FIXME: need to implement mapper code generation
+ getOpenMPRuntime().emitUserDefinedMapper(D, CGF);
}
void CodeGenModule::EmitOMPRequiresDecl(const OMPRequiresDecl *D) {
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 7a0605b8450a..bf16b7bec4b1 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -73,16 +73,10 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D,
// that isn't balanced out by a destructor call as intended by the
// attribute. This also checks for -fno-c++-static-destructors and
// bails even if the attribute is not present.
- if (D.isNoDestroy(CGF.getContext()))
- return;
-
- CodeGenModule &CGM = CGF.CGM;
+ QualType::DestructionKind DtorKind = D.needsDestruction(CGF.getContext());
// FIXME: __attribute__((cleanup)) ?
- QualType Type = D.getType();
- QualType::DestructionKind DtorKind = Type.isDestructedType();
-
switch (DtorKind) {
case QualType::DK_none:
return;
@@ -101,6 +95,9 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D,
llvm::FunctionCallee Func;
llvm::Constant *Argument;
+ CodeGenModule &CGM = CGF.CGM;
+ QualType Type = D.getType();
+
// Special-case non-array C++ destructors, if they have the right signature.
// Under some ABIs, destructors return this instead of void, and cannot be
// passed directly to __cxa_atexit if the target does not allow this
@@ -251,8 +248,8 @@ llvm::Function *CodeGenFunction::createAtExitStub(const VarDecl &VD,
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.getCallee()->stripPointerCasts()))
+ if (auto *dtorFn = dyn_cast<llvm::Function>(
+ dtor.getCallee()->stripPointerCastsAndAliases()))
call->setCallingConv(dtorFn->getCallingConv());
CGF.FinishFunction();
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 3b7a88a0b769..645d7a878e3b 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -165,10 +165,7 @@ static const EHPersonality &getCXXPersonality(const TargetInfo &Target,
return EHPersonality::GNU_CPlusPlus;
if (L.SEHExceptions)
return EHPersonality::GNU_CPlusPlus_SEH;
- // Wasm EH is a non-MVP feature for now.
- if (Target.hasFeature("exception-handling") &&
- (T.getArch() == llvm::Triple::wasm32 ||
- T.getArch() == llvm::Triple::wasm64))
+ if (L.WasmExceptions)
return EHPersonality::GNU_Wasm_CPlusPlus;
return EHPersonality::GNU_CPlusPlus;
}
@@ -1774,7 +1771,8 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
// EH registration is passed in as the EBP physical register. We can
// recover that with llvm.frameaddress(1).
EntryFP = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::frameaddress), {Builder.getInt32(1)});
+ CGM.getIntrinsic(llvm::Intrinsic::frameaddress, AllocaInt8PtrTy),
+ {Builder.getInt32(1)});
} else {
// Otherwise, for x64 and 32-bit finally functions, the parent FP is the
// second parameter.
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 5a4b1188b711..dcd365c8eaf0 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -66,7 +66,7 @@ Address CodeGenFunction::CreateTempAllocaWithoutCast(llvm::Type *Ty,
const Twine &Name,
llvm::Value *ArraySize) {
auto Alloca = CreateTempAlloca(Ty, Name, ArraySize);
- Alloca->setAlignment(Align.getQuantity());
+ Alloca->setAlignment(Align.getAsAlign());
return Address(Alloca, Align);
}
@@ -126,7 +126,7 @@ Address CodeGenFunction::CreateDefaultAlignTempAlloca(llvm::Type *Ty,
void CodeGenFunction::InitTempAlloca(Address Var, llvm::Value *Init) {
assert(isa<llvm::AllocaInst>(Var.getPointer()));
auto *Store = new llvm::StoreInst(Init, Var.getPointer());
- Store->setAlignment(Var.getAlignment().getQuantity());
+ Store->setAlignment(Var.getAlignment().getAsAlign());
llvm::BasicBlock *Block = AllocaInsertPt->getParent();
Block->getInstList().insertAfter(AllocaInsertPt->getIterator(), Store);
}
@@ -392,7 +392,7 @@ static Address createReferenceTemporary(CodeGenFunction &CGF,
llvm::GlobalValue::NotThreadLocal,
CGF.getContext().getTargetAddressSpace(AS));
CharUnits alignment = CGF.getContext().getTypeAlignInChars(Ty);
- GV->setAlignment(alignment.getQuantity());
+ GV->setAlignment(alignment.getAsAlign());
llvm::Constant *C = GV;
if (AS != LangAS::Default)
C = TCG.performAddrSpaceCast(
@@ -516,13 +516,13 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
// Avoid creating a conditional cleanup just to hold an llvm.lifetime.end
// marker. Instead, start the lifetime of a conditional temporary earlier
- // so that it's unconditional. Don't do this in ASan's use-after-scope
- // mode so that it gets the more precise lifetime marks. If the type has
- // a non-trivial destructor, we'll have a cleanup block for it anyway,
- // so this typically doesn't help; skip it in that case.
+ // so that it's unconditional. Don't do this with sanitizers which need
+ // more precise lifetime marks.
ConditionalEvaluation *OldConditional = nullptr;
CGBuilderTy::InsertPoint OldIP;
if (isInConditionalBranch() && !E->getType().isDestructedType() &&
+ !SanOpts.has(SanitizerKind::HWAddress) &&
+ !SanOpts.has(SanitizerKind::Memory) &&
!CGM.getCodeGenOpts().SanitizeAddressUseAfterScope) {
OldConditional = OutermostConditional;
OutermostConditional = nullptr;
@@ -677,8 +677,7 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
// Quickly determine whether we have a pointer to an alloca. It's possible
// to skip null checks, and some alignment checks, for these pointers. This
// can reduce compile-time significantly.
- auto PtrToAlloca =
- dyn_cast<llvm::AllocaInst>(Ptr->stripPointerCastsNoFollowAliases());
+ auto PtrToAlloca = dyn_cast<llvm::AllocaInst>(Ptr->stripPointerCasts());
llvm::Value *True = llvm::ConstantInt::getTrue(getLLVMContext());
llvm::Value *IsNonNull = nullptr;
@@ -998,7 +997,7 @@ EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
// Add the inc/dec to the real part.
NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
} else {
- QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType ElemTy = E->getType()->castAs<ComplexType>()->getElementType();
llvm::APFloat FVal(getContext().getFloatTypeSemantics(ElemTy), 1);
if (!isInc)
FVal.changeSign();
@@ -1268,6 +1267,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::CXXOperatorCallExprClass:
case Expr::UserDefinedLiteralClass:
return EmitCallExprLValue(cast<CallExpr>(E));
+ case Expr::CXXRewrittenBinaryOperatorClass:
+ return EmitLValue(cast<CXXRewrittenBinaryOperator>(E)->getSemanticForm());
case Expr::VAArgExprClass:
return EmitVAArgExprLValue(cast<VAArgExpr>(E));
case Expr::DeclRefExprClass:
@@ -2195,7 +2196,7 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
// If ivar is a structure pointer, assigning to field of
// this struct follows gcc's behavior and makes it a non-ivar
// writer-barrier conservatively.
- ExpTy = ExpTy->getAs<PointerType>()->getPointeeType();
+ ExpTy = ExpTy->castAs<PointerType>()->getPointeeType();
if (ExpTy->isRecordType()) {
LV.setObjCIvar(false);
return;
@@ -2231,7 +2232,7 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
// a non-ivar write-barrier.
QualType ExpTy = E->getType();
if (ExpTy->isPointerType())
- ExpTy = ExpTy->getAs<PointerType>()->getPointeeType();
+ ExpTy = ExpTy->castAs<PointerType>()->getPointeeType();
if (ExpTy->isRecordType())
LV.setObjCIvar(false);
}
@@ -2362,7 +2363,7 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
// If it's thread_local, emit a call to its wrapper function instead.
if (VD->getTLSKind() == VarDecl::TLS_Dynamic &&
- CGF.CGM.getCXXABI().usesThreadWrapperFunction())
+ CGF.CGM.getCXXABI().usesThreadWrapperFunction(VD))
return CGF.CGM.getCXXABI().EmitThreadLocalVarDeclLValue(CGF, VD, T);
// Check if the variable is marked as declare target with link clause in
// device codegen.
@@ -2540,6 +2541,11 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
// Spill the constant value to a global.
Addr = CGM.createUnnamedGlobalFrom(*VD, Val,
getContext().getDeclAlign(VD));
+ llvm::Type *VarTy = getTypes().ConvertTypeForMem(VD->getType());
+ auto *PTy = llvm::PointerType::get(
+ VarTy, getContext().getTargetAddressSpace(VD->getType()));
+ if (PTy != Addr.getType())
+ Addr = Builder.CreatePointerBitCastOrAddrSpaceCast(Addr, PTy);
} else {
// Should we be using the alignment of the constant pointer we emitted?
CharUnits Alignment =
@@ -3400,6 +3406,7 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
ArrayRef<llvm::Value *> indices,
QualType eltType, bool inbounds,
bool signedIndices, SourceLocation loc,
+ QualType *arrayType = nullptr,
const llvm::Twine &name = "arrayidx") {
// All the indices except that last must be zero.
#ifndef NDEBUG
@@ -3428,9 +3435,12 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr,
} else {
// Remember the original array subscript for bpf target
unsigned idx = LastIndex->getZExtValue();
+ llvm::DIType *DbgInfo = nullptr;
+ if (arrayType)
+ DbgInfo = CGF.getDebugInfo()->getOrCreateStandaloneType(*arrayType, loc);
eltPtr = CGF.Builder.CreatePreserveArrayAccessIndex(addr.getPointer(),
indices.size() - 1,
- idx);
+ idx, DbgInfo);
}
return Address(eltPtr, eltAlign);
@@ -3567,19 +3577,21 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
auto *Idx = EmitIdxAfterBase(/*Promote*/true);
// Propagate the alignment from the array itself to the result.
+ QualType arrayType = Array->getType();
Addr = emitArraySubscriptGEP(
*this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices,
- E->getExprLoc());
+ E->getExprLoc(), &arrayType);
EltBaseInfo = ArrayLV.getBaseInfo();
EltTBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, E->getType());
} else {
// The base must be a pointer; emit it with an estimate of its alignment.
Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
auto *Idx = EmitIdxAfterBase(/*Promote*/true);
+ QualType ptrType = E->getBase()->getType();
Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(),
!getLangOpts().isSignedOverflowDefined(),
- SignedIndices, E->getExprLoc());
+ SignedIndices, E->getExprLoc(), &ptrType);
}
LValue LV = MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
@@ -3980,9 +3992,19 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
const CGBitFieldInfo &Info = RL.getBitFieldInfo(field);
Address Addr = base.getAddress();
unsigned Idx = RL.getLLVMFieldNo(field);
- if (Idx != 0)
- // For structs, we GEP to the field that the record layout suggests.
- Addr = Builder.CreateStructGEP(Addr, Idx, field->getName());
+ if (!IsInPreservedAIRegion) {
+ if (Idx != 0)
+ // For structs, we GEP to the field that the record layout suggests.
+ Addr = Builder.CreateStructGEP(Addr, Idx, field->getName());
+ } else {
+ const RecordDecl *rec = field->getParent();
+ llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateRecordType(
+ getContext().getRecordType(rec), rec->getLocation());
+ Addr = Builder.CreatePreserveStructAccessIndex(Addr, Idx,
+ getDebugInfoFIndex(rec, field->getFieldIndex()),
+ DbgInfo);
+ }
+
// Get the access type.
llvm::Type *FieldIntTy =
llvm::Type::getIntNTy(getLLVMContext(), Info.StorageSize);
@@ -4051,7 +4073,6 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
unsigned RecordCVR = base.getVRQualifiers();
if (rec->isUnion()) {
// For unions, there is no pointer adjustment.
- assert(!FieldType->isReferenceType() && "union has reference member");
if (CGM.getCodeGenOpts().StrictVTablePointers &&
hasAnyVptr(FieldType, getContext()))
// Because unions can easily skip invariant.barriers, we need to add
@@ -4068,27 +4089,30 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
addr.getPointer(), getDebugInfoFIndex(rec, field->getFieldIndex()), DbgInfo),
addr.getAlignment());
}
- } else {
+ if (FieldType->isReferenceType())
+ addr = Builder.CreateElementBitCast(
+ addr, CGM.getTypes().ConvertTypeForMem(FieldType), field->getName());
+ } else {
if (!IsInPreservedAIRegion)
// For structs, we GEP to the field that the record layout suggests.
addr = emitAddrOfFieldStorage(*this, addr, field);
else
// Remember the original struct field index
addr = emitPreserveStructAccess(*this, addr, field);
+ }
- // If this is a reference field, load the reference right now.
- if (FieldType->isReferenceType()) {
- LValue RefLVal = MakeAddrLValue(addr, FieldType, FieldBaseInfo,
- FieldTBAAInfo);
- if (RecordCVR & Qualifiers::Volatile)
- RefLVal.getQuals().addVolatile();
- addr = EmitLoadOfReference(RefLVal, &FieldBaseInfo, &FieldTBAAInfo);
-
- // Qualifiers on the struct don't apply to the referencee.
- RecordCVR = 0;
- FieldType = FieldType->getPointeeType();
- }
+ // If this is a reference field, load the reference right now.
+ if (FieldType->isReferenceType()) {
+ LValue RefLVal =
+ MakeAddrLValue(addr, FieldType, FieldBaseInfo, FieldTBAAInfo);
+ if (RecordCVR & Qualifiers::Volatile)
+ RefLVal.getQuals().addVolatile();
+ addr = EmitLoadOfReference(RefLVal, &FieldBaseInfo, &FieldTBAAInfo);
+
+ // Qualifiers on the struct don't apply to the referencee.
+ RecordCVR = 0;
+ FieldType = FieldType->getPointeeType();
}
// Make sure that the address is pointing to the right type. This is critical
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 695facd50b67..2f0e4937613f 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -150,6 +150,9 @@ public:
void VisitBinAssign(const BinaryOperator *E);
void VisitBinComma(const BinaryOperator *E);
void VisitBinCmp(const BinaryOperator *E);
+ void VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *E) {
+ Visit(E->getSemanticForm());
+ }
void VisitObjCMessageExpr(ObjCMessageExpr *E);
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
@@ -501,7 +504,7 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
CGM.getContext().getTargetAddressSpace(AS));
Emitter.finalize(GV);
CharUnits Align = CGM.getContext().getTypeAlignInChars(ArrayQTy);
- GV->setAlignment(Align.getQuantity());
+ GV->setAlignment(Align.getAsAlign());
EmitFinalDestCopy(ArrayQTy, CGF.MakeAddrLValue(GV, ArrayQTy, Align));
return;
}
@@ -1495,6 +1498,13 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// initializers throws an exception.
SmallVector<EHScopeStack::stable_iterator, 16> cleanups;
llvm::Instruction *cleanupDominator = nullptr;
+ auto addCleanup = [&](const EHScopeStack::stable_iterator &cleanup) {
+ cleanups.push_back(cleanup);
+ if (!cleanupDominator) // create placeholder once needed
+ cleanupDominator = CGF.Builder.CreateAlignedLoad(
+ CGF.Int8Ty, llvm::Constant::getNullValue(CGF.Int8PtrTy),
+ CharUnits::One());
+ };
unsigned curInitIndex = 0;
@@ -1519,7 +1529,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (QualType::DestructionKind dtorKind =
Base.getType().isDestructedType()) {
CGF.pushDestroy(dtorKind, V, Base.getType());
- cleanups.push_back(CGF.EHStack.stable_begin());
+ addCleanup(CGF.EHStack.stable_begin());
}
}
}
@@ -1596,15 +1606,9 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
= field->getType().isDestructedType()) {
assert(LV.isSimple());
if (CGF.needsEHCleanup(dtorKind)) {
- if (!cleanupDominator)
- cleanupDominator = CGF.Builder.CreateAlignedLoad(
- CGF.Int8Ty,
- llvm::Constant::getNullValue(CGF.Int8PtrTy),
- CharUnits::One()); // placeholder
-
CGF.pushDestroy(EHCleanup, LV.getAddress(), field->getType(),
CGF.getDestroyer(dtorKind), false);
- cleanups.push_back(CGF.EHStack.stable_begin());
+ addCleanup(CGF.EHStack.stable_begin());
pushedCleanup = true;
}
}
@@ -1620,6 +1624,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// Deactivate all the partial cleanups in reverse order, which
// generally means popping them.
+ assert((cleanupDominator || cleanups.empty()) &&
+ "Missing cleanupDominator before deactivating cleanup blocks");
for (unsigned i = cleanups.size(); i != 0; --i)
CGF.DeactivateCleanupBlock(cleanups[i-1], cleanupDominator);
@@ -1756,7 +1762,7 @@ static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
// referencee. InitListExprs for unions and arrays can't have references.
if (const RecordType *RT = E->getType()->getAs<RecordType>()) {
if (!RT->isUnionType()) {
- RecordDecl *SD = E->getType()->getAs<RecordType>()->getDecl();
+ RecordDecl *SD = RT->getDecl();
CharUnits NumNonZeroBytes = CharUnits::Zero();
unsigned ILEElement = 0;
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 5476d13b7c46..114d806d454b 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -382,7 +382,7 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
const CXXRecordDecl *RD;
std::tie(VTable, RD) =
CGM.getCXXABI().LoadVTablePtr(*this, This.getAddress(),
- MD->getParent());
+ CalleeDecl->getParent());
EmitVTablePtrCheckForCall(RD, VTable, CFITCK_NVCall, CE->getBeginLoc());
}
@@ -418,13 +418,10 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
const Expr *BaseExpr = BO->getLHS();
const Expr *MemFnExpr = BO->getRHS();
- const MemberPointerType *MPT =
- MemFnExpr->getType()->castAs<MemberPointerType>();
-
- const FunctionProtoType *FPT =
- MPT->getPointeeType()->castAs<FunctionProtoType>();
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
+ const auto *MPT = MemFnExpr->getType()->castAs<MemberPointerType>();
+ const auto *FPT = MPT->getPointeeType()->castAs<FunctionProtoType>();
+ const auto *RD =
+ cast<CXXRecordDecl>(MPT->getClass()->castAs<RecordType>()->getDecl());
// Emit the 'this' pointer.
Address This = Address::invalid();
@@ -535,7 +532,7 @@ static void EmitNullBaseClassInitialization(CodeGenFunction &CGF,
CharUnits Align = std::max(Layout.getNonVirtualAlignment(),
DestPtr.getAlignment());
- NullVariable->setAlignment(Align.getQuantity());
+ NullVariable->setAlignment(Align.getAsAlign());
Address SrcPtr = Address(CGF.EmitCastToVoidPtr(NullVariable), Align);
@@ -1882,9 +1879,33 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
Dtor = RD->getDestructor();
if (Dtor->isVirtual()) {
- CGF.CGM.getCXXABI().emitVirtualObjectDelete(CGF, DE, Ptr, ElementType,
- Dtor);
- return;
+ bool UseVirtualCall = true;
+ const Expr *Base = DE->getArgument();
+ if (auto *DevirtualizedDtor =
+ dyn_cast_or_null<const CXXDestructorDecl>(
+ Dtor->getDevirtualizedMethod(
+ Base, CGF.CGM.getLangOpts().AppleKext))) {
+ UseVirtualCall = false;
+ const CXXRecordDecl *DevirtualizedClass =
+ DevirtualizedDtor->getParent();
+ if (declaresSameEntity(getCXXRecord(Base), DevirtualizedClass)) {
+ // Devirtualized to the class of the base type (the type of the
+ // whole expression).
+ Dtor = DevirtualizedDtor;
+ } else {
+ // Devirtualized to some other type. Would need to cast the this
+ // pointer to that type but we don't have support for that yet, so
+ // do a virtual call. FIXME: handle the case where it is
+ // devirtualized to the derived type (the type of the inner
+ // expression) as in EmitCXXMemberOrOperatorMemberCallExpr.
+ UseVirtualCall = true;
+ }
+ }
+ if (UseVirtualCall) {
+ CGF.CGM.getCXXABI().emitVirtualObjectDelete(CGF, DE, Ptr, ElementType,
+ Dtor);
+ return;
+ }
}
}
}
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 6a5fb45ba259..385f87f12a9b 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -279,6 +279,10 @@ public:
return EmitBinDiv(EmitBinOps(E));
}
+ ComplexPairTy VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *E) {
+ return Visit(E->getSemanticForm());
+ }
+
// Compound assignments.
ComplexPairTy VisitBinAddAssign(const CompoundAssignOperator *E) {
return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinAdd);
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 31cf2aef1ba0..96e8c9c0d0e6 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -659,7 +659,7 @@ static bool EmitDesignatedInitUpdater(ConstantEmitter &Emitter,
}
bool ConstStructBuilder::Build(InitListExpr *ILE, bool AllowOverwrite) {
- RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = ILE->getType()->castAs<RecordType>()->getDecl();
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
unsigned FieldNo = -1;
@@ -839,7 +839,7 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
}
llvm::Constant *ConstStructBuilder::Finalize(QualType Type) {
- RecordDecl *RD = Type->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
llvm::Type *ValTy = CGM.getTypes().ConvertType(Type);
return Builder.build(ValTy, RD->hasFlexibleArrayMember());
}
@@ -907,7 +907,7 @@ static ConstantAddress tryEmitGlobalCompoundLiteral(CodeGenModule &CGM,
llvm::GlobalVariable::NotThreadLocal,
CGM.getContext().getTargetAddressSpace(addressSpace));
emitter.finalize(GV);
- GV->setAlignment(Align.getQuantity());
+ GV->setAlignment(Align.getAsAlign());
CGM.setAddrOfConstantCompoundLiteral(E, GV);
return ConstantAddress(GV, Align);
}
@@ -1269,8 +1269,8 @@ public:
return nullptr;
// FIXME: We should not have to call getBaseElementType here.
- const RecordType *RT =
- CGM.getContext().getBaseElementType(Ty)->getAs<RecordType>();
+ const auto *RT =
+ CGM.getContext().getBaseElementType(Ty)->castAs<RecordType>();
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
// If the class doesn't have a trivial destructor, we can't emit it as a
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 3d082de2a14f..55a413a2a717 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -294,8 +294,7 @@ public:
Value *AlignmentValue = CGF.EmitScalarExpr(AVAttr->getAlignment());
llvm::ConstantInt *AlignmentCI = cast<llvm::ConstantInt>(AlignmentValue);
- CGF.EmitAlignmentAssumption(V, E, AVAttr->getLocation(),
- AlignmentCI->getZExtValue());
+ CGF.EmitAlignmentAssumption(V, E, AVAttr->getLocation(), AlignmentCI);
}
/// EmitLoadOfLValue - Given an expression with complex type that represents a
@@ -674,6 +673,10 @@ public:
return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
}
+ Value *VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E) {
+ return Builder.getInt1(E->isSatisfied());
+ }
+
Value *VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) {
return llvm::ConstantInt::get(Builder.getInt32Ty(), E->getValue());
}
@@ -814,6 +817,10 @@ public:
Value *VisitBinPtrMemD(const Expr *E) { return EmitLoadOfLValue(E); }
Value *VisitBinPtrMemI(const Expr *E) { return EmitLoadOfLValue(E); }
+ Value *VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *E) {
+ return Visit(E->getSemanticForm());
+ }
+
// Other Operators.
Value *VisitBlockExpr(const BlockExpr *BE);
Value *VisitAbstractConditionalOperator(const AbstractConditionalOperator *);
@@ -1657,8 +1664,8 @@ Value *ScalarExprEmitter::VisitConvertVectorExpr(ConvertVectorExpr *E) {
if (SrcTy == DstTy)
return Src;
- QualType SrcEltType = SrcType->getAs<VectorType>()->getElementType(),
- DstEltType = DstType->getAs<VectorType>()->getElementType();
+ QualType SrcEltType = SrcType->castAs<VectorType>()->getElementType(),
+ DstEltType = DstType->castAs<VectorType>()->getElementType();
assert(SrcTy->isVectorTy() &&
"ConvertVector source IR type must be a vector");
@@ -2577,14 +2584,16 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
TestAndClearIgnoreResultAssign();
+ Value *Op = Visit(E->getSubExpr());
+
+ // Generate a unary FNeg for FP ops.
+ if (Op->getType()->isFPOrFPVectorTy())
+ return Builder.CreateFNeg(Op, "fneg");
+
// Emit unary minus with EmitSub so we handle overflow cases etc.
BinOpInfo BinOp;
- BinOp.RHS = Visit(E->getSubExpr());
-
- if (BinOp.RHS->getType()->isFPOrFPVectorTy())
- BinOp.LHS = llvm::ConstantFP::getZeroValueForNegation(BinOp.RHS->getType());
- else
- BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType());
+ BinOp.RHS = Op;
+ BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType());
BinOp.Ty = E->getType();
BinOp.Opcode = BO_Sub;
// FIXME: once UnaryOperator carries FPFeatures, copy it here.
@@ -2662,7 +2671,7 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) {
case OffsetOfNode::Field: {
FieldDecl *MemberDecl = ON.getField();
- RecordDecl *RD = CurrentType->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = CurrentType->castAs<RecordType>()->getDecl();
const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD);
// Compute the index of the field in its parent.
@@ -2695,7 +2704,7 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) {
continue;
}
- RecordDecl *RD = CurrentType->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = CurrentType->castAs<RecordType>()->getDecl();
const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD);
// Save the element type.
@@ -3745,7 +3754,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,
Value *FirstVecArg = LHS,
*SecondVecArg = RHS;
- QualType ElTy = LHSTy->getAs<VectorType>()->getElementType();
+ QualType ElTy = LHSTy->castAs<VectorType>()->getElementType();
const BuiltinType *BTy = ElTy->getAs<BuiltinType>();
BuiltinType::Kind ElementKind = BTy->getKind();
@@ -4414,8 +4423,8 @@ Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
return Src;
}
- return Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(),
- Src, DstTy, "astype");
+ return createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(),
+ Src, DstTy, "astype");
}
Value *ScalarExprEmitter::VisitAtomicExpr(AtomicExpr *E) {
@@ -4533,32 +4542,43 @@ LValue CodeGenFunction::EmitCompoundAssignmentLValue(
llvm_unreachable("Unhandled compound assignment operator");
}
-Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr,
- ArrayRef<Value *> IdxList,
- bool SignedIndices,
- bool IsSubtraction,
- SourceLocation Loc,
- const Twine &Name) {
- Value *GEPVal = Builder.CreateInBoundsGEP(Ptr, IdxList, Name);
+struct GEPOffsetAndOverflow {
+ // The total (signed) byte offset for the GEP.
+ llvm::Value *TotalOffset;
+ // The offset overflow flag - true if the total offset overflows.
+ llvm::Value *OffsetOverflows;
+};
- // If the pointer overflow sanitizer isn't enabled, do nothing.
- if (!SanOpts.has(SanitizerKind::PointerOverflow))
- return GEPVal;
+/// Evaluate given GEPVal, which is either an inbounds GEP, or a constant,
+/// and compute the total offset it applies from it's base pointer BasePtr.
+/// Returns offset in bytes and a boolean flag whether an overflow happened
+/// during evaluation.
+static GEPOffsetAndOverflow EmitGEPOffsetInBytes(Value *BasePtr, Value *GEPVal,
+ llvm::LLVMContext &VMContext,
+ CodeGenModule &CGM,
+ CGBuilderTy Builder) {
+ const auto &DL = CGM.getDataLayout();
- // If the GEP has already been reduced to a constant, leave it be.
- if (isa<llvm::Constant>(GEPVal))
- return GEPVal;
+ // The total (signed) byte offset for the GEP.
+ llvm::Value *TotalOffset = nullptr;
- // Only check for overflows in the default address space.
- if (GEPVal->getType()->getPointerAddressSpace())
- return GEPVal;
+ // Was the GEP already reduced to a constant?
+ if (isa<llvm::Constant>(GEPVal)) {
+ // Compute the offset by casting both pointers to integers and subtracting:
+ // GEPVal = BasePtr + ptr(Offset) <--> Offset = int(GEPVal) - int(BasePtr)
+ Value *BasePtr_int =
+ Builder.CreatePtrToInt(BasePtr, DL.getIntPtrType(BasePtr->getType()));
+ Value *GEPVal_int =
+ Builder.CreatePtrToInt(GEPVal, DL.getIntPtrType(GEPVal->getType()));
+ TotalOffset = Builder.CreateSub(GEPVal_int, BasePtr_int);
+ return {TotalOffset, /*OffsetOverflows=*/Builder.getFalse()};
+ }
auto *GEP = cast<llvm::GEPOperator>(GEPVal);
+ assert(GEP->getPointerOperand() == BasePtr &&
+ "BasePtr must be the the base of the GEP.");
assert(GEP->isInBounds() && "Expected inbounds GEP");
- SanitizerScope SanScope(this);
- auto &VMContext = getLLVMContext();
- const auto &DL = CGM.getDataLayout();
auto *IntPtrTy = DL.getIntPtrType(GEP->getPointerOperandType());
// Grab references to the signed add/mul overflow intrinsics for intptr_t.
@@ -4568,8 +4588,6 @@ Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr,
auto *SMulIntrinsic =
CGM.getIntrinsic(llvm::Intrinsic::smul_with_overflow, IntPtrTy);
- // The total (signed) byte offset for the GEP.
- llvm::Value *TotalOffset = nullptr;
// The offset overflow flag - true if the total offset overflows.
llvm::Value *OffsetOverflows = Builder.getFalse();
@@ -4627,41 +4645,122 @@ Value *CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr,
TotalOffset = eval(BO_Add, TotalOffset, LocalOffset);
}
- // Common case: if the total offset is zero, don't emit a check.
- if (TotalOffset == Zero)
+ return {TotalOffset, OffsetOverflows};
+}
+
+Value *
+CodeGenFunction::EmitCheckedInBoundsGEP(Value *Ptr, ArrayRef<Value *> IdxList,
+ bool SignedIndices, bool IsSubtraction,
+ SourceLocation Loc, const Twine &Name) {
+ Value *GEPVal = Builder.CreateInBoundsGEP(Ptr, IdxList, Name);
+
+ // If the pointer overflow sanitizer isn't enabled, do nothing.
+ if (!SanOpts.has(SanitizerKind::PointerOverflow))
+ return GEPVal;
+
+ llvm::Type *PtrTy = Ptr->getType();
+
+ // Perform nullptr-and-offset check unless the nullptr is defined.
+ bool PerformNullCheck = !NullPointerIsDefined(
+ Builder.GetInsertBlock()->getParent(), PtrTy->getPointerAddressSpace());
+ // Check for overflows unless the GEP got constant-folded,
+ // and only in the default address space
+ bool PerformOverflowCheck =
+ !isa<llvm::Constant>(GEPVal) && PtrTy->getPointerAddressSpace() == 0;
+
+ if (!(PerformNullCheck || PerformOverflowCheck))
+ return GEPVal;
+
+ const auto &DL = CGM.getDataLayout();
+
+ SanitizerScope SanScope(this);
+ llvm::Type *IntPtrTy = DL.getIntPtrType(PtrTy);
+
+ GEPOffsetAndOverflow EvaluatedGEP =
+ EmitGEPOffsetInBytes(Ptr, GEPVal, getLLVMContext(), CGM, Builder);
+
+ assert((!isa<llvm::Constant>(EvaluatedGEP.TotalOffset) ||
+ EvaluatedGEP.OffsetOverflows == Builder.getFalse()) &&
+ "If the offset got constant-folded, we don't expect that there was an "
+ "overflow.");
+
+ auto *Zero = llvm::ConstantInt::getNullValue(IntPtrTy);
+
+ // Common case: if the total offset is zero, and we are using C++ semantics,
+ // where nullptr+0 is defined, don't emit a check.
+ if (EvaluatedGEP.TotalOffset == Zero && CGM.getLangOpts().CPlusPlus)
return GEPVal;
// Now that we've computed the total offset, add it to the base pointer (with
// wrapping semantics).
- auto *IntPtr = Builder.CreatePtrToInt(GEP->getPointerOperand(), IntPtrTy);
- auto *ComputedGEP = Builder.CreateAdd(IntPtr, TotalOffset);
-
- // The GEP is valid if:
- // 1) The total offset doesn't overflow, and
- // 2) The sign of the difference between the computed address and the base
- // pointer matches the sign of the total offset.
- llvm::Value *ValidGEP;
- auto *NoOffsetOverflow = Builder.CreateNot(OffsetOverflows);
- if (SignedIndices) {
- auto *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr);
- auto *PosOrZeroOffset = Builder.CreateICmpSGE(TotalOffset, Zero);
- llvm::Value *NegValid = Builder.CreateICmpULT(ComputedGEP, IntPtr);
- ValidGEP = Builder.CreateAnd(
- Builder.CreateSelect(PosOrZeroOffset, PosOrZeroValid, NegValid),
- NoOffsetOverflow);
- } else if (!SignedIndices && !IsSubtraction) {
- auto *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr);
- ValidGEP = Builder.CreateAnd(PosOrZeroValid, NoOffsetOverflow);
- } else {
- auto *NegOrZeroValid = Builder.CreateICmpULE(ComputedGEP, IntPtr);
- ValidGEP = Builder.CreateAnd(NegOrZeroValid, NoOffsetOverflow);
+ auto *IntPtr = Builder.CreatePtrToInt(Ptr, IntPtrTy);
+ auto *ComputedGEP = Builder.CreateAdd(IntPtr, EvaluatedGEP.TotalOffset);
+
+ llvm::SmallVector<std::pair<llvm::Value *, SanitizerMask>, 2> Checks;
+
+ if (PerformNullCheck) {
+ // In C++, if the base pointer evaluates to a null pointer value,
+ // the only valid pointer this inbounds GEP can produce is also
+ // a null pointer, so the offset must also evaluate to zero.
+ // Likewise, if we have non-zero base pointer, we can not get null pointer
+ // as a result, so the offset can not be -intptr_t(BasePtr).
+ // In other words, both pointers are either null, or both are non-null,
+ // or the behaviour is undefined.
+ //
+ // C, however, is more strict in this regard, and gives more
+ // optimization opportunities: in C, additionally, nullptr+0 is undefined.
+ // So both the input to the 'gep inbounds' AND the output must not be null.
+ auto *BaseIsNotNullptr = Builder.CreateIsNotNull(Ptr);
+ auto *ResultIsNotNullptr = Builder.CreateIsNotNull(ComputedGEP);
+ auto *Valid =
+ CGM.getLangOpts().CPlusPlus
+ ? Builder.CreateICmpEQ(BaseIsNotNullptr, ResultIsNotNullptr)
+ : Builder.CreateAnd(BaseIsNotNullptr, ResultIsNotNullptr);
+ Checks.emplace_back(Valid, SanitizerKind::PointerOverflow);
+ }
+
+ if (PerformOverflowCheck) {
+ // The GEP is valid if:
+ // 1) The total offset doesn't overflow, and
+ // 2) The sign of the difference between the computed address and the base
+ // pointer matches the sign of the total offset.
+ llvm::Value *ValidGEP;
+ auto *NoOffsetOverflow = Builder.CreateNot(EvaluatedGEP.OffsetOverflows);
+ if (SignedIndices) {
+ // GEP is computed as `unsigned base + signed offset`, therefore:
+ // * If offset was positive, then the computed pointer can not be
+ // [unsigned] less than the base pointer, unless it overflowed.
+ // * If offset was negative, then the computed pointer can not be
+ // [unsigned] greater than the bas pointere, unless it overflowed.
+ auto *PosOrZeroValid = Builder.CreateICmpUGE(ComputedGEP, IntPtr);
+ auto *PosOrZeroOffset =
+ Builder.CreateICmpSGE(EvaluatedGEP.TotalOffset, Zero);
+ llvm::Value *NegValid = Builder.CreateICmpULT(ComputedGEP, IntPtr);
+ ValidGEP =
+ Builder.CreateSelect(PosOrZeroOffset, PosOrZeroValid, NegValid);
+ } else if (!IsSubtraction) {
+ // GEP is computed as `unsigned base + unsigned offset`, therefore the
+ // computed pointer can not be [unsigned] less than base pointer,
+ // unless there was an overflow.
+ // Equivalent to `@llvm.uadd.with.overflow(%base, %offset)`.
+ ValidGEP = Builder.CreateICmpUGE(ComputedGEP, IntPtr);
+ } else {
+ // GEP is computed as `unsigned base - unsigned offset`, therefore the
+ // computed pointer can not be [unsigned] greater than base pointer,
+ // unless there was an overflow.
+ // Equivalent to `@llvm.usub.with.overflow(%base, sub(0, %offset))`.
+ ValidGEP = Builder.CreateICmpULE(ComputedGEP, IntPtr);
+ }
+ ValidGEP = Builder.CreateAnd(ValidGEP, NoOffsetOverflow);
+ Checks.emplace_back(ValidGEP, SanitizerKind::PointerOverflow);
}
+ assert(!Checks.empty() && "Should have produced some checks.");
+
llvm::Constant *StaticArgs[] = {EmitCheckSourceLocation(Loc)};
// Pass the computed GEP to the runtime to avoid emitting poisoned arguments.
llvm::Value *DynamicArgs[] = {IntPtr, ComputedGEP};
- EmitCheck(std::make_pair(ValidGEP, SanitizerKind::PointerOverflow),
- SanitizerHandler::PointerOverflow, StaticArgs, DynamicArgs);
+ EmitCheck(Checks, SanitizerHandler::PointerOverflow, StaticArgs, DynamicArgs);
return GEPVal;
}
diff --git a/lib/CodeGen/CGLoopInfo.cpp b/lib/CodeGen/CGLoopInfo.cpp
index b2bc42bfa013..c21d4feee7a8 100644
--- a/lib/CodeGen/CGLoopInfo.cpp
+++ b/lib/CodeGen/CGLoopInfo.cpp
@@ -218,6 +218,7 @@ LoopInfo::createLoopVectorizeMetadata(const LoopAttributes &Attrs,
if (Attrs.VectorizeEnable == LoopAttributes::Disable)
Enabled = false;
else if (Attrs.VectorizeEnable != LoopAttributes::Unspecified ||
+ Attrs.VectorizePredicateEnable != LoopAttributes::Unspecified ||
Attrs.InterleaveCount != 0 || Attrs.VectorizeWidth != 0)
Enabled = true;
@@ -251,8 +252,32 @@ LoopInfo::createLoopVectorizeMetadata(const LoopAttributes &Attrs,
Args.push_back(TempNode.get());
Args.append(LoopProperties.begin(), LoopProperties.end());
+ // Setting vectorize.predicate
+ bool IsVectorPredicateEnabled = false;
+ if (Attrs.VectorizePredicateEnable != LoopAttributes::Unspecified &&
+ Attrs.VectorizeEnable != LoopAttributes::Disable &&
+ Attrs.VectorizeWidth < 1) {
+
+ IsVectorPredicateEnabled =
+ (Attrs.VectorizePredicateEnable == LoopAttributes::Enable);
+
+ Metadata *Vals[] = {
+ MDString::get(Ctx, "llvm.loop.vectorize.predicate.enable"),
+ ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt1Ty(Ctx),
+ IsVectorPredicateEnabled))};
+ Args.push_back(MDNode::get(Ctx, Vals));
+ }
+
// Setting vectorize.width
if (Attrs.VectorizeWidth > 0) {
+ // This implies vectorize.enable = true, but only add it when it is not
+ // already enabled.
+ if (Attrs.VectorizeEnable != LoopAttributes::Enable)
+ Args.push_back(
+ MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.vectorize.enable"),
+ ConstantAsMetadata::get(ConstantInt::get(
+ llvm::Type::getInt1Ty(Ctx), 1))}));
+
Metadata *Vals[] = {
MDString::get(Ctx, "llvm.loop.vectorize.width"),
ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt32Ty(Ctx),
@@ -270,12 +295,15 @@ LoopInfo::createLoopVectorizeMetadata(const LoopAttributes &Attrs,
}
// Setting vectorize.enable
- if (Attrs.VectorizeEnable != LoopAttributes::Unspecified) {
+ if (Attrs.VectorizeEnable != LoopAttributes::Unspecified ||
+ IsVectorPredicateEnabled) {
Metadata *Vals[] = {
MDString::get(Ctx, "llvm.loop.vectorize.enable"),
ConstantAsMetadata::get(ConstantInt::get(
llvm::Type::getInt1Ty(Ctx),
- (Attrs.VectorizeEnable == LoopAttributes::Enable)))};
+ IsVectorPredicateEnabled
+ ? true
+ : (Attrs.VectorizeEnable == LoopAttributes::Enable)))};
Args.push_back(MDNode::get(Ctx, Vals));
}
@@ -411,7 +439,8 @@ MDNode *LoopInfo::createMetadata(
LoopAttributes::LoopAttributes(bool IsParallel)
: IsParallel(IsParallel), VectorizeEnable(LoopAttributes::Unspecified),
UnrollEnable(LoopAttributes::Unspecified),
- UnrollAndJamEnable(LoopAttributes::Unspecified), VectorizeWidth(0),
+ UnrollAndJamEnable(LoopAttributes::Unspecified),
+ VectorizePredicateEnable(LoopAttributes::Unspecified), VectorizeWidth(0),
InterleaveCount(0), UnrollCount(0), UnrollAndJamCount(0),
DistributeEnable(LoopAttributes::Unspecified), PipelineDisabled(false),
PipelineInitiationInterval(0) {}
@@ -425,6 +454,7 @@ void LoopAttributes::clear() {
VectorizeEnable = LoopAttributes::Unspecified;
UnrollEnable = LoopAttributes::Unspecified;
UnrollAndJamEnable = LoopAttributes::Unspecified;
+ VectorizePredicateEnable = LoopAttributes::Unspecified;
DistributeEnable = LoopAttributes::Unspecified;
PipelineDisabled = false;
PipelineInitiationInterval = 0;
@@ -446,6 +476,7 @@ LoopInfo::LoopInfo(BasicBlock *Header, const LoopAttributes &Attrs,
Attrs.InterleaveCount == 0 && Attrs.UnrollCount == 0 &&
Attrs.UnrollAndJamCount == 0 && !Attrs.PipelineDisabled &&
Attrs.PipelineInitiationInterval == 0 &&
+ Attrs.VectorizePredicateEnable == LoopAttributes::Unspecified &&
Attrs.VectorizeEnable == LoopAttributes::Unspecified &&
Attrs.UnrollEnable == LoopAttributes::Unspecified &&
Attrs.UnrollAndJamEnable == LoopAttributes::Unspecified &&
@@ -480,6 +511,7 @@ void LoopInfo::finish() {
BeforeJam.InterleaveCount = Attrs.InterleaveCount;
BeforeJam.VectorizeEnable = Attrs.VectorizeEnable;
BeforeJam.DistributeEnable = Attrs.DistributeEnable;
+ BeforeJam.VectorizePredicateEnable = Attrs.VectorizePredicateEnable;
switch (Attrs.UnrollEnable) {
case LoopAttributes::Unspecified:
@@ -495,6 +527,7 @@ void LoopInfo::finish() {
break;
}
+ AfterJam.VectorizePredicateEnable = Attrs.VectorizePredicateEnable;
AfterJam.UnrollCount = Attrs.UnrollCount;
AfterJam.PipelineDisabled = Attrs.PipelineDisabled;
AfterJam.PipelineInitiationInterval = Attrs.PipelineInitiationInterval;
@@ -516,6 +549,7 @@ void LoopInfo::finish() {
// add it manually.
SmallVector<Metadata *, 1> BeforeLoopProperties;
if (BeforeJam.VectorizeEnable != LoopAttributes::Unspecified ||
+ BeforeJam.VectorizePredicateEnable != LoopAttributes::Unspecified ||
BeforeJam.InterleaveCount != 0 || BeforeJam.VectorizeWidth != 0)
BeforeLoopProperties.push_back(
MDNode::get(Ctx, MDString::get(Ctx, "llvm.loop.isvectorized")));
@@ -537,8 +571,9 @@ void LoopInfo::finish() {
void LoopInfoStack::push(BasicBlock *Header, const llvm::DebugLoc &StartLoc,
const llvm::DebugLoc &EndLoc) {
- Active.push_back(LoopInfo(Header, StagedAttrs, StartLoc, EndLoc,
- Active.empty() ? nullptr : &Active.back()));
+ Active.emplace_back(
+ new LoopInfo(Header, StagedAttrs, StartLoc, EndLoc,
+ Active.empty() ? nullptr : Active.back().get()));
// Clear the attributes so nested loops do not inherit them.
StagedAttrs.clear();
}
@@ -603,6 +638,9 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
case LoopHintAttr::UnrollAndJam:
setUnrollAndJamState(LoopAttributes::Disable);
break;
+ case LoopHintAttr::VectorizePredicate:
+ setVectorizePredicateState(LoopAttributes::Disable);
+ break;
case LoopHintAttr::Distribute:
setDistributeState(false);
break;
@@ -630,6 +668,9 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
case LoopHintAttr::UnrollAndJam:
setUnrollAndJamState(LoopAttributes::Enable);
break;
+ case LoopHintAttr::VectorizePredicate:
+ setVectorizePredicateState(LoopAttributes::Enable);
+ break;
case LoopHintAttr::Distribute:
setDistributeState(true);
break;
@@ -653,6 +694,7 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
break;
case LoopHintAttr::Unroll:
case LoopHintAttr::UnrollAndJam:
+ case LoopHintAttr::VectorizePredicate:
case LoopHintAttr::UnrollCount:
case LoopHintAttr::UnrollAndJamCount:
case LoopHintAttr::VectorizeWidth:
@@ -681,6 +723,7 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
case LoopHintAttr::Distribute:
case LoopHintAttr::PipelineDisabled:
case LoopHintAttr::PipelineInitiationInterval:
+ case LoopHintAttr::VectorizePredicate:
llvm_unreachable("Options cannot be used with 'full' hint.");
break;
}
@@ -704,6 +747,7 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
break;
case LoopHintAttr::Unroll:
case LoopHintAttr::UnrollAndJam:
+ case LoopHintAttr::VectorizePredicate:
case LoopHintAttr::Vectorize:
case LoopHintAttr::Interleave:
case LoopHintAttr::Distribute:
@@ -721,16 +765,16 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
void LoopInfoStack::pop() {
assert(!Active.empty() && "No active loops to pop");
- Active.back().finish();
+ Active.back()->finish();
Active.pop_back();
}
void LoopInfoStack::InsertHelper(Instruction *I) const {
if (I->mayReadOrWriteMemory()) {
SmallVector<Metadata *, 4> AccessGroups;
- for (const LoopInfo &AL : Active) {
+ for (const auto &AL : Active) {
// Here we assume that every loop that has an access group is parallel.
- if (MDNode *Group = AL.getAccessGroup())
+ if (MDNode *Group = AL->getAccessGroup())
AccessGroups.push_back(Group);
}
MDNode *UnionMD = nullptr;
diff --git a/lib/CodeGen/CGLoopInfo.h b/lib/CodeGen/CGLoopInfo.h
index 35d0e00527b9..5abcf37c5433 100644
--- a/lib/CodeGen/CGLoopInfo.h
+++ b/lib/CodeGen/CGLoopInfo.h
@@ -51,6 +51,9 @@ struct LoopAttributes {
/// Value for llvm.loop.unroll_and_jam.* metadata (enable, disable, or full).
LVEnableState UnrollAndJamEnable;
+ /// Value for llvm.loop.vectorize.predicate metadata
+ LVEnableState VectorizePredicateEnable;
+
/// Value for llvm.loop.vectorize.width metadata.
unsigned VectorizeWidth;
@@ -237,6 +240,11 @@ public:
StagedAttrs.UnrollEnable = State;
}
+ /// Set the next pushed vectorize predicate state.
+ void setVectorizePredicateState(const LoopAttributes::LVEnableState &State) {
+ StagedAttrs.VectorizePredicateEnable = State;
+ }
+
/// Set the next pushed loop unroll_and_jam state.
void setUnrollAndJamState(const LoopAttributes::LVEnableState &State) {
StagedAttrs.UnrollAndJamEnable = State;
@@ -267,11 +275,11 @@ private:
bool hasInfo() const { return !Active.empty(); }
/// Return the LoopInfo for the current loop. HasInfo should be called
/// first to ensure LoopInfo is present.
- const LoopInfo &getInfo() const { return Active.back(); }
+ const LoopInfo &getInfo() const { return *Active.back(); }
/// The set of attributes that will be applied to the next pushed loop.
LoopAttributes StagedAttrs;
/// Stack of active loops.
- llvm::SmallVector<LoopInfo, 4> Active;
+ llvm::SmallVector<std::unique_ptr<LoopInfo>, 4> Active;
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/CGNonTrivialStruct.cpp b/lib/CodeGen/CGNonTrivialStruct.cpp
index caf62d2ac93a..05615aa12881 100644
--- a/lib/CodeGen/CGNonTrivialStruct.cpp
+++ b/lib/CodeGen/CGNonTrivialStruct.cpp
@@ -823,7 +823,7 @@ static void callSpecialFunction(G &&Gen, StringRef FuncName, QualType QT,
Gen.callFunc(FuncName, QT, Addrs, CGF);
}
-template <size_t N> std::array<Address, N> createNullAddressArray();
+template <size_t N> static std::array<Address, N> createNullAddressArray();
template <> std::array<Address, 1> createNullAddressArray() {
return std::array<Address, 1>({{Address(nullptr, CharUnits::Zero())}});
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 1dd7ec52230e..1fa72678081a 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -143,7 +143,7 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
NumElements);
QualType ElementType = Context.getObjCIdType().withConst();
QualType ElementArrayType
- = Context.getConstantArrayType(ElementType, APNumElements,
+ = Context.getConstantArrayType(ElementType, APNumElements, nullptr,
ArrayType::Normal, /*IndexTypeQuals=*/0);
// Allocate the temporary array(s).
@@ -1661,7 +1661,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
QualType ItemsTy =
getContext().getConstantArrayType(getContext().getObjCIdType(),
- llvm::APInt(32, NumItems),
+ llvm::APInt(32, NumItems), nullptr,
ArrayType::Normal, 0);
Address ItemsPtr = CreateMemTemp(ItemsTy, "items.ptr");
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index ee5c12aa35bd..d2c089d0360e 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -1294,7 +1294,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
// Emit a placeholder symbol.
GV = new llvm::GlobalVariable(TheModule, ProtocolTy, false,
llvm::GlobalValue::ExternalLinkage, nullptr, Name);
- GV->setAlignment(CGM.getPointerAlign().getQuantity());
+ GV->setAlignment(CGM.getPointerAlign().getAsAlign());
}
return llvm::ConstantExpr::getBitCast(GV, ProtocolPtrTy);
}
@@ -1318,7 +1318,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
llvm::ConstantExpr::getBitCast(Protocol, ProtocolPtrTy), RefName);
GV->setComdat(TheModule.getOrInsertComdat(RefName));
GV->setSection(sectionName<ProtocolReferenceSection>());
- GV->setAlignment(CGM.getPointerAlign().getQuantity());
+ GV->setAlignment(CGM.getPointerAlign().getAsAlign());
Ref = GV;
}
EmittedProtocolRef = true;
@@ -1497,7 +1497,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
Sym->setSection((Section + SecSuffix).str());
Sym->setComdat(TheModule.getOrInsertComdat((Prefix +
Section).str()));
- Sym->setAlignment(CGM.getPointerAlign().getQuantity());
+ Sym->setAlignment(CGM.getPointerAlign().getAsAlign());
return Sym;
};
return { Sym("__start_", "$a"), Sym("__stop", "$z") };
@@ -1854,7 +1854,8 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
ivarBuilder.addInt(Int32Ty,
CGM.getContext().getTypeSizeInChars(ivarTy).getQuantity());
// Alignment will be stored as a base-2 log of the alignment.
- int align = llvm::Log2_32(Context.getTypeAlignInChars(ivarTy).getQuantity());
+ unsigned align =
+ llvm::Log2_32(Context.getTypeAlignInChars(ivarTy).getQuantity());
// Objects that require more than 2^64-byte alignment should be impossible!
assert(align < 64);
// uint32_t flags;
@@ -4039,7 +4040,7 @@ LValue CGObjCGNU::EmitObjCValueForIvar(CodeGenFunction &CGF,
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers) {
const ObjCInterfaceDecl *ID =
- ObjectTy->getAs<ObjCObjectType>()->getInterface();
+ ObjectTy->castAs<ObjCObjectType>()->getInterface();
return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
EmitIvarOffset(CGF, ID, Ivar));
}
@@ -4086,7 +4087,7 @@ llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF,
auto GV = new llvm::GlobalVariable(TheModule, IntTy,
false, llvm::GlobalValue::LinkOnceAnyLinkage,
llvm::Constant::getNullValue(IntTy), name);
- GV->setAlignment(Align.getQuantity());
+ GV->setAlignment(Align.getAsAlign());
Offset = GV;
}
Offset = CGF.Builder.CreateAlignedLoad(Offset, Align);
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 12880fecbadf..8e28b2f05c16 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -2018,7 +2018,7 @@ CGObjCCommonMac::GenerateConstantNSString(const StringLiteral *Literal) {
GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
// Don't enforce the target's minimum global alignment, since the only use
// of the string is via this class initializer.
- GV->setAlignment(1);
+ GV->setAlignment(llvm::Align::None());
Fields.addBitCast(GV, CGM.Int8PtrTy);
// String length.
@@ -2517,14 +2517,12 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
}
if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
- const ConstantArrayType *CArray =
- dyn_cast_or_null<ConstantArrayType>(Array);
+ auto *CArray = cast<ConstantArrayType>(Array);
uint64_t ElCount = CArray->getSize().getZExtValue();
assert(CArray && "only array with known element size is supported");
FQT = CArray->getElementType();
while (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
- const ConstantArrayType *CArray =
- dyn_cast_or_null<ConstantArrayType>(Array);
+ auto *CArray = cast<ConstantArrayType>(Array);
ElCount *= CArray->getSize().getZExtValue();
FQT = CArray->getElementType();
}
@@ -3103,7 +3101,7 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) {
nullptr, "OBJC_PROTOCOL_" + PD->getName());
Entry->setSection("__OBJC,__protocol,regular,no_dead_strip");
// FIXME: Is this necessary? Why only for protocol?
- Entry->setAlignment(4);
+ Entry->setAlignment(llvm::Align(4));
}
return Entry;
@@ -3609,7 +3607,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
"Forward metaclass reference has incorrect type.");
values.finishAndSetAsInitializer(GV);
GV->setSection(Section);
- GV->setAlignment(CGM.getPointerAlign().getQuantity());
+ GV->setAlignment(CGM.getPointerAlign().getAsAlign());
CGM.addCompilerUsedGlobal(GV);
} else
GV = CreateMetadataVar(Name, values, Section, CGM.getPointerAlign(), true);
@@ -4016,7 +4014,7 @@ llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name,
new llvm::GlobalVariable(CGM.getModule(), Ty, false, LT, Init, Name);
if (!Section.empty())
GV->setSection(Section);
- GV->setAlignment(Align.getQuantity());
+ GV->setAlignment(Align.getAsAlign());
if (AddToUsed)
CGM.addCompilerUsedGlobal(GV);
return GV;
@@ -4064,7 +4062,7 @@ CGObjCCommonMac::CreateCStringLiteral(StringRef Name, ObjCLabelType Type,
if (CGM.getTriple().isOSBinFormatMachO())
GV->setSection(Section);
GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
- GV->setAlignment(CharUnits::One().getQuantity());
+ GV->setAlignment(CharUnits::One().getAsAlign());
CGM.addCompilerUsedGlobal(GV);
return GV;
@@ -4902,7 +4900,7 @@ LValue CGObjCMac::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF,
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers) {
const ObjCInterfaceDecl *ID =
- ObjectTy->getAs<ObjCObjectType>()->getInterface();
+ ObjectTy->castAs<ObjCObjectType>()->getInterface();
return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
EmitIvarOffset(CGF, ID, Ivar));
}
@@ -6076,7 +6074,8 @@ void CGObjCNonFragileABIMac::AddModuleClassList(
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, LT, Init,
SymbolName);
- GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType()));
+ GV->setAlignment(
+ llvm::Align(CGM.getDataLayout().getABITypeAlignment(Init->getType())));
GV->setSection(SectionName);
CGM.addCompilerUsedGlobal(GV);
}
@@ -6319,8 +6318,8 @@ CGObjCNonFragileABIMac::BuildClassObject(const ObjCInterfaceDecl *CI,
if (CGM.getTriple().isOSBinFormatMachO())
GV->setSection("__DATA, __objc_data");
- GV->setAlignment(
- CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABITy));
+ GV->setAlignment(llvm::Align(
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABITy)));
if (!CGM.getTriple().isOSBinFormatCOFF())
if (HiddenVisibility)
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
@@ -6527,7 +6526,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF,
PTGV->setSection(GetSectionName("__objc_protorefs",
"coalesced,no_dead_strip"));
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
- PTGV->setAlignment(Align.getQuantity());
+ PTGV->setAlignment(Align.getAsAlign());
if (!CGM.getTriple().isOSBinFormatMachO())
PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolName));
CGM.addUsedGlobal(PTGV);
@@ -6759,8 +6758,8 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
llvm::GlobalVariable *IvarOffsetGV = ObjCIvarOffsetVariable(ID, Ivar);
IvarOffsetGV->setInitializer(
llvm::ConstantInt::get(ObjCTypes.IvarOffsetVarTy, Offset));
- IvarOffsetGV->setAlignment(
- CGM.getDataLayout().getABITypeAlignment(ObjCTypes.IvarOffsetVarTy));
+ IvarOffsetGV->setAlignment(llvm::Align(
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.IvarOffsetVarTy)));
if (!CGM.getTriple().isOSBinFormatCOFF()) {
// FIXME: This matches gcc, but shouldn't the visibility be set on the use
@@ -6986,8 +6985,8 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
ProtocolRef);
if (!CGM.getTriple().isOSBinFormatMachO())
PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolRef));
- PTGV->setAlignment(
- CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
+ PTGV->setAlignment(llvm::Align(
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)));
PTGV->setSection(GetSectionName("__objc_protolist",
"coalesced,no_dead_strip"));
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
@@ -7053,7 +7052,7 @@ LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar(
llvm::Value *BaseValue,
const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers) {
- ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCObjectType>()->getInterface();
+ ObjCInterfaceDecl *ID = ObjectTy->castAs<ObjCObjectType>()->getInterface();
llvm::Value *Offset = EmitIvarOffset(CGF, ID, Ivar);
return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
Offset);
@@ -7338,7 +7337,7 @@ CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF,
CGM.getModule(), ClassGV->getType(), false,
getLinkageTypeForObjCMetadata(CGM, SectionName), ClassGV,
"OBJC_CLASSLIST_REFERENCES_$_");
- Entry->setAlignment(CGF.getPointerAlign().getQuantity());
+ Entry->setAlignment(CGF.getPointerAlign().getAsAlign());
if (!ID || !ID->hasAttr<ObjCClassStubAttr>())
Entry->setSection(SectionName);
@@ -7377,7 +7376,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
CGM.getModule(), ClassGV->getType(), false,
getLinkageTypeForObjCMetadata(CGM, SectionName), ClassGV,
"OBJC_CLASSLIST_SUP_REFS_$_");
- Entry->setAlignment(CGF.getPointerAlign().getQuantity());
+ Entry->setAlignment(CGF.getPointerAlign().getAsAlign());
Entry->setSection(SectionName);
CGM.addCompilerUsedGlobal(Entry);
}
@@ -7401,7 +7400,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF,
CGM.getModule(), ObjCTypes.ClassnfABIPtrTy, false,
getLinkageTypeForObjCMetadata(CGM, SectionName), MetaClassGV,
"OBJC_CLASSLIST_SUP_REFS_$_");
- Entry->setAlignment(Align.getQuantity());
+ Entry->setAlignment(Align.getAsAlign());
Entry->setSection(SectionName);
CGM.addCompilerUsedGlobal(Entry);
}
@@ -7500,7 +7499,7 @@ Address CGObjCNonFragileABIMac::EmitSelectorAddr(CodeGenFunction &CGF,
"OBJC_SELECTOR_REFERENCES_");
Entry->setExternallyInitialized(true);
Entry->setSection(SectionName);
- Entry->setAlignment(Align.getQuantity());
+ Entry->setAlignment(Align.getAsAlign());
CGM.addCompilerUsedGlobal(Entry);
}
@@ -7733,7 +7732,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
: llvm::GlobalValue::WeakAnyLinkage;
if (Entry) {
values.finishAndSetAsInitializer(Entry);
- Entry->setAlignment(CGM.getPointerAlign().getQuantity());
+ Entry->setAlignment(CGM.getPointerAlign().getAsAlign());
} else {
Entry = values.finishAndCreateGlobal("OBJC_EHTYPE_$_" + ClassName,
CGM.getPointerAlign(),
diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp
index 27e7175da841..2a13a2a58156 100644
--- a/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -752,6 +752,11 @@ enum OpenMPRTLFunction {
// arg_num, void** args_base, void **args, int64_t *arg_sizes, int64_t
// *arg_types);
OMPRTL__tgt_target_data_update_nowait,
+ // Call to int64_t __tgt_mapper_num_components(void *rt_mapper_handle);
+ OMPRTL__tgt_mapper_num_components,
+ // Call to void __tgt_push_mapper_component(void *rt_mapper_handle, void
+ // *base, void *begin, int64_t size, int64_t type);
+ OMPRTL__tgt_push_mapper_component,
};
/// A basic class for pre|post-action for advanced codegen sequence for OpenMP
@@ -1259,6 +1264,52 @@ CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM, StringRef FirstSeparator,
loadOffloadInfoMetadata();
}
+bool CGOpenMPRuntime::tryEmitDeclareVariant(const GlobalDecl &NewGD,
+ const GlobalDecl &OldGD,
+ llvm::GlobalValue *OrigAddr,
+ bool IsForDefinition) {
+ // Emit at least a definition for the aliasee if the the address of the
+ // original function is requested.
+ if (IsForDefinition || OrigAddr)
+ (void)CGM.GetAddrOfGlobal(NewGD);
+ StringRef NewMangledName = CGM.getMangledName(NewGD);
+ llvm::GlobalValue *Addr = CGM.GetGlobalValue(NewMangledName);
+ if (Addr && !Addr->isDeclaration()) {
+ const auto *D = cast<FunctionDecl>(OldGD.getDecl());
+ const CGFunctionInfo &FI = CGM.getTypes().arrangeGlobalDeclaration(OldGD);
+ llvm::Type *DeclTy = CGM.getTypes().GetFunctionType(FI);
+
+ // Create a reference to the named value. This ensures that it is emitted
+ // if a deferred decl.
+ llvm::GlobalValue::LinkageTypes LT = CGM.getFunctionLinkage(OldGD);
+
+ // Create the new alias itself, but don't set a name yet.
+ auto *GA =
+ llvm::GlobalAlias::create(DeclTy, 0, LT, "", Addr, &CGM.getModule());
+
+ if (OrigAddr) {
+ assert(OrigAddr->isDeclaration() && "Expected declaration");
+
+ GA->takeName(OrigAddr);
+ OrigAddr->replaceAllUsesWith(
+ llvm::ConstantExpr::getBitCast(GA, OrigAddr->getType()));
+ OrigAddr->eraseFromParent();
+ } else {
+ GA->setName(CGM.getMangledName(OldGD));
+ }
+
+ // Set attributes which are particular to an alias; this is a
+ // specialization of the attributes which may be set on a global function.
+ if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakRefAttr>() ||
+ D->isWeakImported())
+ GA->setLinkage(llvm::Function::WeakAnyLinkage);
+
+ CGM.SetCommonAttributes(OldGD, GA);
+ return true;
+ }
+ return false;
+}
+
void CGOpenMPRuntime::clear() {
InternalVars.clear();
// Clean non-target variable declarations possibly used only in debug info.
@@ -1272,6 +1323,14 @@ void CGOpenMPRuntime::clear() {
continue;
GV->eraseFromParent();
}
+ // Emit aliases for the deferred aliasees.
+ for (const auto &Pair : DeferredVariantFunction) {
+ StringRef MangledName = CGM.getMangledName(Pair.second.second);
+ llvm::GlobalValue *Addr = CGM.GetGlobalValue(MangledName);
+ // If not able to emit alias, just emit original declaration.
+ (void)tryEmitDeclareVariant(Pair.second.first, Pair.second.second, Addr,
+ /*IsForDefinition=*/false);
+ }
}
std::string CGOpenMPRuntime::getName(ArrayRef<StringRef> Parts) const {
@@ -1638,18 +1697,23 @@ llvm::Value *CGOpenMPRuntime::getThreadID(CodeGenFunction &CGF,
return ThreadID;
}
// If exceptions are enabled, do not use parameter to avoid possible crash.
- if (!CGF.EHStack.requiresLandingPad() || !CGF.getLangOpts().Exceptions ||
- !CGF.getLangOpts().CXXExceptions ||
- CGF.Builder.GetInsertBlock() == CGF.AllocaInsertPt->getParent()) {
- if (auto *OMPRegionInfo =
- dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
- if (OMPRegionInfo->getThreadIDVariable()) {
- // Check if this an outlined function with thread id passed as argument.
- LValue LVal = OMPRegionInfo->getThreadIDVariableLValue(CGF);
+ if (auto *OMPRegionInfo =
+ dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
+ if (OMPRegionInfo->getThreadIDVariable()) {
+ // Check if this an outlined function with thread id passed as argument.
+ LValue LVal = OMPRegionInfo->getThreadIDVariableLValue(CGF);
+ llvm::BasicBlock *TopBlock = CGF.AllocaInsertPt->getParent();
+ if (!CGF.EHStack.requiresLandingPad() || !CGF.getLangOpts().Exceptions ||
+ !CGF.getLangOpts().CXXExceptions ||
+ CGF.Builder.GetInsertBlock() == TopBlock ||
+ !isa<llvm::Instruction>(LVal.getPointer()) ||
+ cast<llvm::Instruction>(LVal.getPointer())->getParent() == TopBlock ||
+ cast<llvm::Instruction>(LVal.getPointer())->getParent() ==
+ CGF.Builder.GetInsertBlock()) {
ThreadID = CGF.EmitLoadOfScalar(LVal, Loc);
// If value loaded in entry block, cache it and use it everywhere in
// function.
- if (CGF.Builder.GetInsertBlock() == CGF.AllocaInsertPt->getParent()) {
+ if (CGF.Builder.GetInsertBlock() == TopBlock) {
auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn);
Elem.second.ThreadID = ThreadID;
}
@@ -1686,6 +1750,12 @@ void CGOpenMPRuntime::functionFinished(CodeGenFunction &CGF) {
UDRMap.erase(D);
FunctionUDRMap.erase(CGF.CurFn);
}
+ auto I = FunctionUDMMap.find(CGF.CurFn);
+ if (I != FunctionUDMMap.end()) {
+ for(auto *D : I->second)
+ UDMMap.erase(D);
+ FunctionUDMMap.erase(I);
+ }
}
llvm::Type *CGOpenMPRuntime::getIdentTyPointerTy() {
@@ -2459,6 +2529,24 @@ llvm::FunctionCallee CGOpenMPRuntime::createRuntimeFunction(unsigned Function) {
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_target_data_update_nowait");
break;
}
+ case OMPRTL__tgt_mapper_num_components: {
+ // Build int64_t __tgt_mapper_num_components(void *rt_mapper_handle);
+ llvm::Type *TypeParams[] = {CGM.VoidPtrTy};
+ auto *FnTy =
+ llvm::FunctionType::get(CGM.Int64Ty, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_mapper_num_components");
+ break;
+ }
+ case OMPRTL__tgt_push_mapper_component: {
+ // Build void __tgt_push_mapper_component(void *rt_mapper_handle, void
+ // *base, void *begin, int64_t size, int64_t type);
+ llvm::Type *TypeParams[] = {CGM.VoidPtrTy, CGM.VoidPtrTy, CGM.VoidPtrTy,
+ CGM.Int64Ty, CGM.Int64Ty};
+ auto *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_push_mapper_component");
+ break;
+ }
}
assert(RTLFn && "Unable to find OpenMP runtime function");
return RTLFn;
@@ -2552,6 +2640,32 @@ CGOpenMPRuntime::createDispatchNextFunction(unsigned IVSize, bool IVSigned) {
return CGM.CreateRuntimeFunction(FnTy, Name);
}
+/// Obtain information that uniquely identifies a target entry. This
+/// consists of the file and device IDs as well as line number associated with
+/// the relevant entry source location.
+static void getTargetEntryUniqueInfo(ASTContext &C, SourceLocation Loc,
+ unsigned &DeviceID, unsigned &FileID,
+ unsigned &LineNum) {
+ SourceManager &SM = C.getSourceManager();
+
+ // The loc should be always valid and have a file ID (the user cannot use
+ // #pragma directives in macros)
+
+ assert(Loc.isValid() && "Source location is expected to be always valid.");
+
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+ assert(PLoc.isValid() && "Source location is expected to be always valid.");
+
+ llvm::sys::fs::UniqueID ID;
+ if (auto EC = llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID))
+ SM.getDiagnostics().Report(diag::err_cannot_open_file)
+ << PLoc.getFilename() << EC.message();
+
+ DeviceID = ID.getDevice();
+ FileID = ID.getFile();
+ LineNum = PLoc.getLine();
+}
+
Address CGOpenMPRuntime::getAddrOfDeclareTargetVar(const VarDecl *VD) {
if (CGM.getLangOpts().OpenMPSimd)
return Address::invalid();
@@ -2563,19 +2677,27 @@ Address CGOpenMPRuntime::getAddrOfDeclareTargetVar(const VarDecl *VD) {
SmallString<64> PtrName;
{
llvm::raw_svector_ostream OS(PtrName);
- OS << CGM.getMangledName(GlobalDecl(VD)) << "_decl_tgt_ref_ptr";
+ OS << CGM.getMangledName(GlobalDecl(VD));
+ if (!VD->isExternallyVisible()) {
+ unsigned DeviceID, FileID, Line;
+ getTargetEntryUniqueInfo(CGM.getContext(),
+ VD->getCanonicalDecl()->getBeginLoc(),
+ DeviceID, FileID, Line);
+ OS << llvm::format("_%x", FileID);
+ }
+ OS << "_decl_tgt_ref_ptr";
}
llvm::Value *Ptr = CGM.getModule().getNamedValue(PtrName);
if (!Ptr) {
QualType PtrTy = CGM.getContext().getPointerType(VD->getType());
Ptr = getOrCreateInternalVariable(CGM.getTypes().ConvertTypeForMem(PtrTy),
PtrName);
- if (!CGM.getLangOpts().OpenMPIsDevice) {
- auto *GV = cast<llvm::GlobalVariable>(Ptr);
- GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
+
+ auto *GV = cast<llvm::GlobalVariable>(Ptr);
+ GV->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
+
+ if (!CGM.getLangOpts().OpenMPIsDevice)
GV->setInitializer(CGM.GetAddrOfGlobal(VD));
- }
- CGM.addUsedGlobal(cast<llvm::GlobalValue>(Ptr));
registerTargetGlobalVariable(VD, cast<llvm::Constant>(Ptr));
}
return Address(Ptr, CGM.getContext().getDeclAlign(VD));
@@ -2749,35 +2871,12 @@ llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition(
return nullptr;
}
-/// Obtain information that uniquely identifies a target entry. This
-/// consists of the file and device IDs as well as line number associated with
-/// the relevant entry source location.
-static void getTargetEntryUniqueInfo(ASTContext &C, SourceLocation Loc,
- unsigned &DeviceID, unsigned &FileID,
- unsigned &LineNum) {
- SourceManager &SM = C.getSourceManager();
-
- // The loc should be always valid and have a file ID (the user cannot use
- // #pragma directives in macros)
-
- assert(Loc.isValid() && "Source location is expected to be always valid.");
-
- PresumedLoc PLoc = SM.getPresumedLoc(Loc);
- assert(PLoc.isValid() && "Source location is expected to be always valid.");
-
- llvm::sys::fs::UniqueID ID;
- if (auto EC = llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID))
- SM.getDiagnostics().Report(diag::err_cannot_open_file)
- << PLoc.getFilename() << EC.message();
-
- DeviceID = ID.getDevice();
- FileID = ID.getFile();
- LineNum = PLoc.getLine();
-}
-
bool CGOpenMPRuntime::emitDeclareTargetVarDefinition(const VarDecl *VD,
llvm::GlobalVariable *Addr,
bool PerformInit) {
+ if (CGM.getLangOpts().OMPTargetTriples.empty() &&
+ !CGM.getLangOpts().OpenMPIsDevice)
+ return false;
Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (!Res || *Res == OMPDeclareTargetDeclAttr::MT_Link ||
@@ -2981,14 +3080,16 @@ void CGOpenMPRuntime::emitParallelCall(CodeGenFunction &CGF, SourceLocation Loc,
CGF.EmitRuntimeCall(
RT.createRuntimeFunction(OMPRTL__kmpc_serialized_parallel), Args);
- // OutlinedFn(&GTid, &zero, CapturedStruct);
- Address ZeroAddr = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty,
- /*Name*/ ".zero.addr");
- CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0));
+ // OutlinedFn(&GTid, &zero_bound, CapturedStruct);
+ Address ThreadIDAddr = RT.emitThreadIDAddress(CGF, Loc);
+ Address ZeroAddrBound =
+ CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty,
+ /*Name=*/".bound.zero.addr");
+ CGF.InitTempAlloca(ZeroAddrBound, CGF.Builder.getInt32(/*C*/ 0));
llvm::SmallVector<llvm::Value *, 16> OutlinedFnArgs;
// ThreadId for serialized parallels is 0.
- OutlinedFnArgs.push_back(ZeroAddr.getPointer());
- OutlinedFnArgs.push_back(ZeroAddr.getPointer());
+ OutlinedFnArgs.push_back(ThreadIDAddr.getPointer());
+ OutlinedFnArgs.push_back(ZeroAddrBound.getPointer());
OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end());
RT.emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs);
@@ -3283,9 +3384,9 @@ void CGOpenMPRuntime::emitSingleRegion(CodeGenFunction &CGF,
// <copy_func>, did_it);
if (DidIt.isValid()) {
llvm::APInt ArraySize(/*unsigned int numBits=*/32, CopyprivateVars.size());
- QualType CopyprivateArrayTy =
- C.getConstantArrayType(C.VoidPtrTy, ArraySize, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
+ QualType CopyprivateArrayTy = C.getConstantArrayType(
+ C.VoidPtrTy, ArraySize, nullptr, ArrayType::Normal,
+ /*IndexTypeQuals=*/0);
// Create a list of all private variables for copyprivate.
Address CopyprivateList =
CGF.CreateMemTemp(CopyprivateArrayTy, ".omp.copyprivate.cpr_list");
@@ -3472,7 +3573,7 @@ bool CGOpenMPRuntime::isDynamic(OpenMPScheduleClauseKind ScheduleKind) const {
return Schedule != OMP_sch_static;
}
-static int addMonoNonMonoModifier(OpenMPSchedType Schedule,
+static int addMonoNonMonoModifier(CodeGenModule &CGM, OpenMPSchedType Schedule,
OpenMPScheduleClauseModifier M1,
OpenMPScheduleClauseModifier M2) {
int Modifier = 0;
@@ -3506,6 +3607,18 @@ static int addMonoNonMonoModifier(OpenMPSchedType Schedule,
case OMPC_SCHEDULE_MODIFIER_unknown:
break;
}
+ // OpenMP 5.0, 2.9.2 Worksharing-Loop Construct, Desription.
+ // If the static schedule kind is specified or if the ordered clause is
+ // specified, and if the nonmonotonic modifier is not specified, the effect is
+ // as if the monotonic modifier is specified. Otherwise, unless the monotonic
+ // modifier is specified, the effect is as if the nonmonotonic modifier is
+ // specified.
+ if (CGM.getLangOpts().OpenMP >= 50 && Modifier == 0) {
+ if (!(Schedule == OMP_sch_static_chunked || Schedule == OMP_sch_static ||
+ Schedule == OMP_sch_static_balanced_chunked ||
+ Schedule == OMP_ord_static_chunked || Schedule == OMP_ord_static))
+ Modifier = OMP_sch_modifier_nonmonotonic;
+ }
return Schedule | Modifier;
}
@@ -3530,13 +3643,14 @@ void CGOpenMPRuntime::emitForDispatchInit(
llvm::Value *Chunk = DispatchValues.Chunk ? DispatchValues.Chunk
: CGF.Builder.getIntN(IVSize, 1);
llvm::Value *Args[] = {
- emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
+ emitUpdateLocation(CGF, Loc),
+ getThreadID(CGF, Loc),
CGF.Builder.getInt32(addMonoNonMonoModifier(
- Schedule, ScheduleKind.M1, ScheduleKind.M2)), // Schedule type
- DispatchValues.LB, // Lower
- DispatchValues.UB, // Upper
- CGF.Builder.getIntN(IVSize, 1), // Stride
- Chunk // Chunk
+ CGM, Schedule, ScheduleKind.M1, ScheduleKind.M2)), // Schedule type
+ DispatchValues.LB, // Lower
+ DispatchValues.UB, // Upper
+ CGF.Builder.getIntN(IVSize, 1), // Stride
+ Chunk // Chunk
};
CGF.EmitRuntimeCall(createDispatchInitFunction(IVSize, IVSigned), Args);
}
@@ -3578,7 +3692,7 @@ static void emitForStaticInitCall(
llvm::Value *Args[] = {
UpdateLocation,
ThreadId,
- CGF.Builder.getInt32(addMonoNonMonoModifier(Schedule, M1,
+ CGF.Builder.getInt32(addMonoNonMonoModifier(CGF.CGM, Schedule, M1,
M2)), // Schedule type
Values.IL.getPointer(), // &isLastIter
Values.LB.getPointer(), // &LB
@@ -3899,157 +4013,6 @@ void CGOpenMPRuntime::OffloadEntriesInfoManagerTy::
Action(E.getKey(), E.getValue());
}
-llvm::Function *
-CGOpenMPRuntime::createOffloadingBinaryDescriptorRegistration() {
- // If we don't have entries or if we are emitting code for the device, we
- // don't need to do anything.
- if (CGM.getLangOpts().OpenMPIsDevice || OffloadEntriesInfoManager.empty())
- return nullptr;
-
- llvm::Module &M = CGM.getModule();
- ASTContext &C = CGM.getContext();
-
- // Get list of devices we care about
- const std::vector<llvm::Triple> &Devices = CGM.getLangOpts().OMPTargetTriples;
-
- // We should be creating an offloading descriptor only if there are devices
- // specified.
- assert(!Devices.empty() && "No OpenMP offloading devices??");
-
- // Create the external variables that will point to the begin and end of the
- // host entries section. These will be defined by the linker.
- llvm::Type *OffloadEntryTy =
- CGM.getTypes().ConvertTypeForMem(getTgtOffloadEntryQTy());
- std::string EntriesBeginName = getName({"omp_offloading", "entries_begin"});
- auto *HostEntriesBegin = new llvm::GlobalVariable(
- M, OffloadEntryTy, /*isConstant=*/true,
- llvm::GlobalValue::ExternalLinkage, /*Initializer=*/nullptr,
- EntriesBeginName);
- std::string EntriesEndName = getName({"omp_offloading", "entries_end"});
- auto *HostEntriesEnd =
- new llvm::GlobalVariable(M, OffloadEntryTy, /*isConstant=*/true,
- llvm::GlobalValue::ExternalLinkage,
- /*Initializer=*/nullptr, EntriesEndName);
-
- // Create all device images
- auto *DeviceImageTy = cast<llvm::StructType>(
- CGM.getTypes().ConvertTypeForMem(getTgtDeviceImageQTy()));
- ConstantInitBuilder DeviceImagesBuilder(CGM);
- ConstantArrayBuilder DeviceImagesEntries =
- DeviceImagesBuilder.beginArray(DeviceImageTy);
-
- for (const llvm::Triple &Device : Devices) {
- StringRef T = Device.getTriple();
- std::string BeginName = getName({"omp_offloading", "img_start", ""});
- auto *ImgBegin = new llvm::GlobalVariable(
- M, CGM.Int8Ty, /*isConstant=*/true,
- llvm::GlobalValue::ExternalWeakLinkage,
- /*Initializer=*/nullptr, Twine(BeginName).concat(T));
- std::string EndName = getName({"omp_offloading", "img_end", ""});
- auto *ImgEnd = new llvm::GlobalVariable(
- M, CGM.Int8Ty, /*isConstant=*/true,
- llvm::GlobalValue::ExternalWeakLinkage,
- /*Initializer=*/nullptr, Twine(EndName).concat(T));
-
- llvm::Constant *Data[] = {ImgBegin, ImgEnd, HostEntriesBegin,
- HostEntriesEnd};
- createConstantGlobalStructAndAddToParent(CGM, getTgtDeviceImageQTy(), Data,
- DeviceImagesEntries);
- }
-
- // Create device images global array.
- std::string ImagesName = getName({"omp_offloading", "device_images"});
- llvm::GlobalVariable *DeviceImages =
- DeviceImagesEntries.finishAndCreateGlobal(ImagesName,
- CGM.getPointerAlign(),
- /*isConstant=*/true);
- DeviceImages->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
-
- // This is a Zero array to be used in the creation of the constant expressions
- llvm::Constant *Index[] = {llvm::Constant::getNullValue(CGM.Int32Ty),
- llvm::Constant::getNullValue(CGM.Int32Ty)};
-
- // Create the target region descriptor.
- llvm::Constant *Data[] = {
- llvm::ConstantInt::get(CGM.Int32Ty, Devices.size()),
- llvm::ConstantExpr::getGetElementPtr(DeviceImages->getValueType(),
- DeviceImages, Index),
- HostEntriesBegin, HostEntriesEnd};
- std::string Descriptor = getName({"omp_offloading", "descriptor"});
- llvm::GlobalVariable *Desc = createGlobalStruct(
- CGM, getTgtBinaryDescriptorQTy(), /*IsConstant=*/true, Data, Descriptor);
-
- // Emit code to register or unregister the descriptor at execution
- // startup or closing, respectively.
-
- llvm::Function *UnRegFn;
- {
- FunctionArgList Args;
- ImplicitParamDecl DummyPtr(C, C.VoidPtrTy, ImplicitParamDecl::Other);
- Args.push_back(&DummyPtr);
-
- CodeGenFunction CGF(CGM);
- // Disable debug info for global (de-)initializer because they are not part
- // of some particular construct.
- CGF.disableDebugInfo();
- const auto &FI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
- std::string UnregName = getName({"omp_offloading", "descriptor_unreg"});
- UnRegFn = CGM.CreateGlobalInitOrDestructFunction(FTy, UnregName, FI);
- CGF.StartFunction(GlobalDecl(), C.VoidTy, UnRegFn, FI, Args);
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__tgt_unregister_lib),
- Desc);
- CGF.FinishFunction();
- }
- llvm::Function *RegFn;
- {
- CodeGenFunction CGF(CGM);
- // Disable debug info for global (de-)initializer because they are not part
- // of some particular construct.
- CGF.disableDebugInfo();
- const auto &FI = CGM.getTypes().arrangeNullaryFunction();
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI);
-
- // Encode offload target triples into the registration function name. It
- // will serve as a comdat key for the registration/unregistration code for
- // this particular combination of offloading targets.
- SmallVector<StringRef, 4U> RegFnNameParts(Devices.size() + 2U);
- RegFnNameParts[0] = "omp_offloading";
- RegFnNameParts[1] = "descriptor_reg";
- llvm::transform(Devices, std::next(RegFnNameParts.begin(), 2),
- [](const llvm::Triple &T) -> const std::string& {
- return T.getTriple();
- });
- llvm::sort(std::next(RegFnNameParts.begin(), 2), RegFnNameParts.end());
- std::string Descriptor = getName(RegFnNameParts);
- RegFn = CGM.CreateGlobalInitOrDestructFunction(FTy, Descriptor, FI);
- CGF.StartFunction(GlobalDecl(), C.VoidTy, RegFn, FI, FunctionArgList());
- CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__tgt_register_lib), Desc);
- // Create a variable to drive the registration and unregistration of the
- // descriptor, so we can reuse the logic that emits Ctors and Dtors.
- ImplicitParamDecl RegUnregVar(C, C.getTranslationUnitDecl(),
- SourceLocation(), nullptr, C.CharTy,
- ImplicitParamDecl::Other);
- CGM.getCXXABI().registerGlobalDtor(CGF, RegUnregVar, UnRegFn, Desc);
- CGF.FinishFunction();
- }
- if (CGM.supportsCOMDAT()) {
- // It is sufficient to call registration function only once, so create a
- // COMDAT group for registration/unregistration functions and associated
- // data. That would reduce startup time and code size. Registration
- // function serves as a COMDAT group key.
- llvm::Comdat *ComdatKey = M.getOrInsertComdat(RegFn->getName());
- RegFn->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
- RegFn->setVisibility(llvm::GlobalValue::HiddenVisibility);
- RegFn->setComdat(ComdatKey);
- UnRegFn->setComdat(ComdatKey);
- DeviceImages->setComdat(ComdatKey);
- Desc->setComdat(ComdatKey);
- }
- return RegFn;
-}
-
void CGOpenMPRuntime::createOffloadEntry(
llvm::Constant *ID, llvm::Constant *Addr, uint64_t Size, int32_t Flags,
llvm::GlobalValue::LinkageTypes Linkage) {
@@ -4077,8 +4040,7 @@ void CGOpenMPRuntime::createOffloadEntry(
Twine(EntryName).concat(Name), llvm::GlobalValue::WeakAnyLinkage);
// The entry has to be created in the section the linker expects it to be.
- std::string Section = getName({"omp_offloading", "entries"});
- Entry->setSection(Section);
+ Entry->setSection("omp_offloading_entries");
}
void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() {
@@ -4091,13 +4053,16 @@ void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() {
// Right now we only generate metadata for function that contain target
// regions.
- // If we do not have entries, we don't need to do anything.
- if (OffloadEntriesInfoManager.empty())
+ // If we are in simd mode or there are no entries, we don't need to do
+ // anything.
+ if (CGM.getLangOpts().OpenMPSimd || OffloadEntriesInfoManager.empty())
return;
llvm::Module &M = CGM.getModule();
llvm::LLVMContext &C = M.getContext();
- SmallVector<const OffloadEntriesInfoManagerTy::OffloadEntryInfo *, 16>
+ SmallVector<std::tuple<const OffloadEntriesInfoManagerTy::OffloadEntryInfo *,
+ SourceLocation, StringRef>,
+ 16>
OrderedEntries(OffloadEntriesInfoManager.size());
llvm::SmallVector<StringRef, 16> ParentFunctions(
OffloadEntriesInfoManager.size());
@@ -4115,7 +4080,8 @@ void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() {
// Create function that emits metadata for each target region entry;
auto &&TargetRegionMetadataEmitter =
- [&C, MD, &OrderedEntries, &ParentFunctions, &GetMDInt, &GetMDString](
+ [this, &C, MD, &OrderedEntries, &ParentFunctions, &GetMDInt,
+ &GetMDString](
unsigned DeviceID, unsigned FileID, StringRef ParentName,
unsigned Line,
const OffloadEntriesInfoManagerTy::OffloadEntryInfoTargetRegion &E) {
@@ -4133,8 +4099,19 @@ void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() {
GetMDInt(FileID), GetMDString(ParentName),
GetMDInt(Line), GetMDInt(E.getOrder())};
+ SourceLocation Loc;
+ for (auto I = CGM.getContext().getSourceManager().fileinfo_begin(),
+ E = CGM.getContext().getSourceManager().fileinfo_end();
+ I != E; ++I) {
+ if (I->getFirst()->getUniqueID().getDevice() == DeviceID &&
+ I->getFirst()->getUniqueID().getFile() == FileID) {
+ Loc = CGM.getContext().getSourceManager().translateFileLineCol(
+ I->getFirst(), Line, 1);
+ break;
+ }
+ }
// Save this entry in the right position of the ordered entries array.
- OrderedEntries[E.getOrder()] = &E;
+ OrderedEntries[E.getOrder()] = std::make_tuple(&E, Loc, ParentName);
ParentFunctions[E.getOrder()] = ParentName;
// Add metadata to the named metadata node.
@@ -4162,7 +4139,8 @@ void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() {
GetMDInt(E.getFlags()), GetMDInt(E.getOrder())};
// Save this entry in the right position of the ordered entries array.
- OrderedEntries[E.getOrder()] = &E;
+ OrderedEntries[E.getOrder()] =
+ std::make_tuple(&E, SourceLocation(), MangledName);
// Add metadata to the named metadata node.
MD->addOperand(llvm::MDNode::get(C, Ops));
@@ -4171,11 +4149,11 @@ void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() {
OffloadEntriesInfoManager.actOnDeviceGlobalVarEntriesInfo(
DeviceGlobalVarMetadataEmitter);
- for (const auto *E : OrderedEntries) {
- assert(E && "All ordered entries must exist!");
+ for (const auto &E : OrderedEntries) {
+ assert(std::get<0>(E) && "All ordered entries must exist!");
if (const auto *CE =
dyn_cast<OffloadEntriesInfoManagerTy::OffloadEntryInfoTargetRegion>(
- E)) {
+ std::get<0>(E))) {
if (!CE->getID() || !CE->getAddress()) {
// Do not blame the entry if the parent funtion is not emitted.
StringRef FnName = ParentFunctions[CE->getOrder()];
@@ -4183,16 +4161,16 @@ void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() {
continue;
unsigned DiagID = CGM.getDiags().getCustomDiagID(
DiagnosticsEngine::Error,
- "Offloading entry for target region is incorrect: either the "
+ "Offloading entry for target region in %0 is incorrect: either the "
"address or the ID is invalid.");
- CGM.getDiags().Report(DiagID);
+ CGM.getDiags().Report(std::get<1>(E), DiagID) << FnName;
continue;
}
createOffloadEntry(CE->getID(), CE->getAddress(), /*Size=*/0,
CE->getFlags(), llvm::GlobalValue::WeakAnyLinkage);
- } else if (const auto *CE =
- dyn_cast<OffloadEntriesInfoManagerTy::
- OffloadEntryInfoDeviceGlobalVar>(E)) {
+ } else if (const auto *CE = dyn_cast<OffloadEntriesInfoManagerTy::
+ OffloadEntryInfoDeviceGlobalVar>(
+ std::get<0>(E))) {
OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryKind Flags =
static_cast<OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryKind>(
CE->getFlags());
@@ -4203,10 +4181,10 @@ void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() {
continue;
if (!CE->getAddress()) {
unsigned DiagID = CGM.getDiags().getCustomDiagID(
- DiagnosticsEngine::Error,
- "Offloading entry for declare target variable is incorrect: the "
- "address is invalid.");
- CGM.getDiags().Report(DiagID);
+ DiagnosticsEngine::Error, "Offloading entry for declare target "
+ "variable %0 is incorrect: the "
+ "address is invalid.");
+ CGM.getDiags().Report(std::get<1>(E), DiagID) << std::get<2>(E);
continue;
}
// The vaiable has no definition - no need to add the entry.
@@ -5242,7 +5220,7 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc,
// Define type kmp_depend_info[<Dependences.size()>];
QualType KmpDependInfoArrayTy = C.getConstantArrayType(
KmpDependInfoTy, llvm::APInt(/*numBits=*/64, NumDependencies),
- ArrayType::Normal, /*IndexTypeQuals=*/0);
+ nullptr, ArrayType::Normal, /*IndexTypeQuals=*/0);
// kmp_depend_info[<Dependences.size()>] deps;
DependenciesArray =
CGF.CreateMemTemp(KmpDependInfoArrayTy, ".dep.arr.addr");
@@ -5763,7 +5741,7 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
}
llvm::APInt ArraySize(/*unsigned int numBits=*/32, Size);
QualType ReductionArrayTy =
- C.getConstantArrayType(C.VoidPtrTy, ArraySize, ArrayType::Normal,
+ C.getConstantArrayType(C.VoidPtrTy, ArraySize, nullptr, ArrayType::Normal,
/*IndexTypeQuals=*/0);
Address ReductionList =
CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list");
@@ -6235,7 +6213,7 @@ llvm::Value *CGOpenMPRuntime::emitTaskReductionInit(
unsigned Size = Data.ReductionVars.size();
llvm::APInt ArraySize(/*numBits=*/64, Size);
QualType ArrayRDType = C.getConstantArrayType(
- RDType, ArraySize, ArrayType::Normal, /*IndexTypeQuals=*/0);
+ RDType, ArraySize, nullptr, ArrayType::Normal, /*IndexTypeQuals=*/0);
// kmp_task_red_input_t .rd_input.[Size];
Address TaskRedInput = CGF.CreateMemTemp(ArrayRDType, ".rd_input.");
ReductionCodeGen RCG(Data.ReductionVars, Data.ReductionCopies,
@@ -6720,12 +6698,16 @@ emitNumTeamsForTargetDirective(CodeGenFunction &CGF,
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_target_update:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_requires:
case OMPD_unknown:
break;
@@ -7025,12 +7007,16 @@ emitNumThreadsForTargetDirective(CodeGenFunction &CGF,
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_target_update:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_requires:
case OMPD_unknown:
break;
@@ -7079,12 +7065,24 @@ public:
OMP_MAP_LITERAL = 0x100,
/// Implicit map
OMP_MAP_IMPLICIT = 0x200,
+ /// Close is a hint to the runtime to allocate memory close to
+ /// the target device.
+ OMP_MAP_CLOSE = 0x400,
/// The 16 MSBs of the flags indicate whether the entry is member of some
/// struct/class.
OMP_MAP_MEMBER_OF = 0xffff000000000000,
LLVM_MARK_AS_BITMASK_ENUM(/* LargestFlag = */ OMP_MAP_MEMBER_OF),
};
+ /// Get the offset of the OMP_MAP_MEMBER_OF field.
+ static unsigned getFlagMemberOffset() {
+ unsigned Offset = 0;
+ for (uint64_t Remain = OMP_MAP_MEMBER_OF; !(Remain & 1);
+ Remain = Remain >> 1)
+ Offset++;
+ return Offset;
+ }
+
/// Class that associates information with a base pointer to be passed to the
/// runtime library.
class BasePointerInfo {
@@ -7148,8 +7146,11 @@ private:
: IE(IE), VD(VD) {}
};
- /// Directive from where the map clauses were extracted.
- const OMPExecutableDirective &CurDir;
+ /// The target directive from where the mappable clauses were extracted. It
+ /// is either a executable directive or a user-defined mapper directive.
+ llvm::PointerUnion<const OMPExecutableDirective *,
+ const OMPDeclareMapperDecl *>
+ CurDir;
/// Function the directive is being generated for.
CodeGenFunction &CGF;
@@ -7181,9 +7182,11 @@ private:
OAE->getBase()->IgnoreParenImpCasts())
.getCanonicalType();
- // If there is no length associated with the expression, that means we
- // are using the whole length of the base.
- if (!OAE->getLength() && OAE->getColonLoc().isValid())
+ // If there is no length associated with the expression and lower bound is
+ // not specified too, that means we are using the whole length of the
+ // base.
+ if (!OAE->getLength() && OAE->getColonLoc().isValid() &&
+ !OAE->getLowerBound())
return CGF.getTypeSize(BaseTy);
llvm::Value *ElemSize;
@@ -7197,13 +7200,30 @@ private:
// If we don't have a length at this point, that is because we have an
// array section with a single element.
- if (!OAE->getLength())
+ if (!OAE->getLength() && OAE->getColonLoc().isInvalid())
return ElemSize;
- llvm::Value *LengthVal = CGF.EmitScalarExpr(OAE->getLength());
- LengthVal =
- CGF.Builder.CreateIntCast(LengthVal, CGF.SizeTy, /*isSigned=*/false);
- return CGF.Builder.CreateNUWMul(LengthVal, ElemSize);
+ if (const Expr *LenExpr = OAE->getLength()) {
+ llvm::Value *LengthVal = CGF.EmitScalarExpr(LenExpr);
+ LengthVal = CGF.EmitScalarConversion(LengthVal, LenExpr->getType(),
+ CGF.getContext().getSizeType(),
+ LenExpr->getExprLoc());
+ return CGF.Builder.CreateNUWMul(LengthVal, ElemSize);
+ }
+ assert(!OAE->getLength() && OAE->getColonLoc().isValid() &&
+ OAE->getLowerBound() && "expected array_section[lb:].");
+ // Size = sizetype - lb * elemtype;
+ llvm::Value *LengthVal = CGF.getTypeSize(BaseTy);
+ llvm::Value *LBVal = CGF.EmitScalarExpr(OAE->getLowerBound());
+ LBVal = CGF.EmitScalarConversion(LBVal, OAE->getLowerBound()->getType(),
+ CGF.getContext().getSizeType(),
+ OAE->getLowerBound()->getExprLoc());
+ LBVal = CGF.Builder.CreateNUWMul(LBVal, ElemSize);
+ llvm::Value *Cmp = CGF.Builder.CreateICmpUGT(LengthVal, LBVal);
+ llvm::Value *TrueVal = CGF.Builder.CreateNUWSub(LengthVal, LBVal);
+ LengthVal = CGF.Builder.CreateSelect(
+ Cmp, TrueVal, llvm::ConstantInt::get(CGF.SizeTy, 0));
+ return LengthVal;
}
return CGF.getTypeSize(ExprTy);
}
@@ -7247,6 +7267,9 @@ private:
if (llvm::find(MapModifiers, OMPC_MAP_MODIFIER_always)
!= MapModifiers.end())
Bits |= OMP_MAP_ALWAYS;
+ if (llvm::find(MapModifiers, OMPC_MAP_MODIFIER_close)
+ != MapModifiers.end())
+ Bits |= OMP_MAP_CLOSE;
return Bits;
}
@@ -7675,10 +7698,10 @@ private:
if (!IsExpressionFirstInfo) {
// If we have a PTR_AND_OBJ pair where the OBJ is a pointer as well,
- // then we reset the TO/FROM/ALWAYS/DELETE flags.
+ // then we reset the TO/FROM/ALWAYS/DELETE/CLOSE flags.
if (IsPointer)
Flags &= ~(OMP_MAP_TO | OMP_MAP_FROM | OMP_MAP_ALWAYS |
- OMP_MAP_DELETE);
+ OMP_MAP_DELETE | OMP_MAP_CLOSE);
if (ShouldBeMemberOf) {
// Set placeholder value MEMBER_OF=FFFF to indicate that the flag
@@ -7752,9 +7775,9 @@ private:
}
static OpenMPOffloadMappingFlags getMemberOfFlag(unsigned Position) {
- // Member of is given by the 16 MSB of the flag, so rotate by 48 bits.
+ // Rotate by getFlagMemberOffset() bits.
return static_cast<OpenMPOffloadMappingFlags>(((uint64_t)Position + 1)
- << 48);
+ << getFlagMemberOffset());
}
static void setCorrectMemberOfFlag(OpenMPOffloadMappingFlags &Flags,
@@ -7834,7 +7857,7 @@ private:
public:
MappableExprsHandler(const OMPExecutableDirective &Dir, CodeGenFunction &CGF)
- : CurDir(Dir), CGF(CGF) {
+ : CurDir(&Dir), CGF(CGF) {
// Extract firstprivate clause information.
for (const auto *C : Dir.getClausesOfKind<OMPFirstprivateClause>())
for (const auto *D : C->varlists())
@@ -7846,6 +7869,10 @@ public:
DevPointersMap[L.first].push_back(L.second);
}
+ /// Constructor for the declare mapper directive.
+ MappableExprsHandler(const OMPDeclareMapperDecl &Dir, CodeGenFunction &CGF)
+ : CurDir(&Dir), CGF(CGF) {}
+
/// Generate code for the combined entry if we have a partially mapped struct
/// and take care of the mapping flags of the arguments corresponding to
/// individual struct members.
@@ -7907,18 +7934,20 @@ public:
IsImplicit);
};
- // FIXME: MSVC 2013 seems to require this-> to find member CurDir.
- for (const auto *C : this->CurDir.getClausesOfKind<OMPMapClause>())
+ assert(CurDir.is<const OMPExecutableDirective *>() &&
+ "Expect a executable directive");
+ const auto *CurExecDir = CurDir.get<const OMPExecutableDirective *>();
+ for (const auto *C : CurExecDir->getClausesOfKind<OMPMapClause>())
for (const auto &L : C->component_lists()) {
InfoGen(L.first, L.second, C->getMapType(), C->getMapTypeModifiers(),
/*ReturnDevicePointer=*/false, C->isImplicit());
}
- for (const auto *C : this->CurDir.getClausesOfKind<OMPToClause>())
+ for (const auto *C : CurExecDir->getClausesOfKind<OMPToClause>())
for (const auto &L : C->component_lists()) {
InfoGen(L.first, L.second, OMPC_MAP_to, llvm::None,
/*ReturnDevicePointer=*/false, C->isImplicit());
}
- for (const auto *C : this->CurDir.getClausesOfKind<OMPFromClause>())
+ for (const auto *C : CurExecDir->getClausesOfKind<OMPFromClause>())
for (const auto &L : C->component_lists()) {
InfoGen(L.first, L.second, OMPC_MAP_from, llvm::None,
/*ReturnDevicePointer=*/false, C->isImplicit());
@@ -7933,9 +7962,8 @@ public:
llvm::MapVector<const ValueDecl *, SmallVector<DeferredDevicePtrEntryTy, 4>>
DeferredInfo;
- // FIXME: MSVC 2013 seems to require this-> to find member CurDir.
for (const auto *C :
- this->CurDir.getClausesOfKind<OMPUseDevicePtrClause>()) {
+ CurExecDir->getClausesOfKind<OMPUseDevicePtrClause>()) {
for (const auto &L : C->component_lists()) {
assert(!L.second.empty() && "Not expecting empty list of components!");
const ValueDecl *VD = L.second.back().getAssociatedDeclaration();
@@ -7964,7 +7992,6 @@ public:
// We didn't find any match in our map information - generate a zero
// size array section - if the pointer is a struct member we defer this
// action until the whole struct has been processed.
- // FIXME: MSVC 2013 seems to require this-> to find member CGF.
if (isa<MemberExpr>(IE)) {
// Insert the pointer into Info to be processed by
// generateInfoForComponentList. Because it is a member pointer
@@ -7977,11 +8004,11 @@ public:
/*ReturnDevicePointer=*/false, C->isImplicit());
DeferredInfo[nullptr].emplace_back(IE, VD);
} else {
- llvm::Value *Ptr = this->CGF.EmitLoadOfScalar(
- this->CGF.EmitLValue(IE), IE->getExprLoc());
+ llvm::Value *Ptr =
+ CGF.EmitLoadOfScalar(CGF.EmitLValue(IE), IE->getExprLoc());
BasePointers.emplace_back(Ptr, VD);
Pointers.push_back(Ptr);
- Sizes.push_back(llvm::Constant::getNullValue(this->CGF.Int64Ty));
+ Sizes.push_back(llvm::Constant::getNullValue(CGF.Int64Ty));
Types.push_back(OMP_MAP_RETURN_PARAM | OMP_MAP_TARGET_PARAM);
}
}
@@ -8005,11 +8032,10 @@ public:
// Remember the current base pointer index.
unsigned CurrentBasePointersIdx = CurBasePointers.size();
- // FIXME: MSVC 2013 seems to require this-> to find the member method.
- this->generateInfoForComponentList(
- L.MapType, L.MapModifiers, L.Components, CurBasePointers,
- CurPointers, CurSizes, CurTypes, PartialStruct,
- IsFirstComponentList, L.IsImplicit);
+ generateInfoForComponentList(L.MapType, L.MapModifiers, L.Components,
+ CurBasePointers, CurPointers, CurSizes,
+ CurTypes, PartialStruct,
+ IsFirstComponentList, L.IsImplicit);
// If this entry relates with a device pointer, set the relevant
// declaration and add the 'return pointer' flag.
@@ -8061,6 +8087,78 @@ public:
}
}
+ /// Generate all the base pointers, section pointers, sizes and map types for
+ /// the extracted map clauses of user-defined mapper.
+ void generateAllInfoForMapper(MapBaseValuesArrayTy &BasePointers,
+ MapValuesArrayTy &Pointers,
+ MapValuesArrayTy &Sizes,
+ MapFlagsArrayTy &Types) const {
+ assert(CurDir.is<const OMPDeclareMapperDecl *>() &&
+ "Expect a declare mapper directive");
+ const auto *CurMapperDir = CurDir.get<const OMPDeclareMapperDecl *>();
+ // We have to process the component lists that relate with the same
+ // declaration in a single chunk so that we can generate the map flags
+ // correctly. Therefore, we organize all lists in a map.
+ llvm::MapVector<const ValueDecl *, SmallVector<MapInfo, 8>> Info;
+
+ // Helper function to fill the information map for the different supported
+ // clauses.
+ auto &&InfoGen = [&Info](
+ const ValueDecl *D,
+ OMPClauseMappableExprCommon::MappableExprComponentListRef L,
+ OpenMPMapClauseKind MapType,
+ ArrayRef<OpenMPMapModifierKind> MapModifiers,
+ bool ReturnDevicePointer, bool IsImplicit) {
+ const ValueDecl *VD =
+ D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr;
+ Info[VD].emplace_back(L, MapType, MapModifiers, ReturnDevicePointer,
+ IsImplicit);
+ };
+
+ for (const auto *C : CurMapperDir->clauselists()) {
+ const auto *MC = cast<OMPMapClause>(C);
+ for (const auto &L : MC->component_lists()) {
+ InfoGen(L.first, L.second, MC->getMapType(), MC->getMapTypeModifiers(),
+ /*ReturnDevicePointer=*/false, MC->isImplicit());
+ }
+ }
+
+ for (const auto &M : Info) {
+ // We need to know when we generate information for the first component
+ // associated with a capture, because the mapping flags depend on it.
+ bool IsFirstComponentList = true;
+
+ // Temporary versions of arrays
+ MapBaseValuesArrayTy CurBasePointers;
+ MapValuesArrayTy CurPointers;
+ MapValuesArrayTy CurSizes;
+ MapFlagsArrayTy CurTypes;
+ StructRangeInfoTy PartialStruct;
+
+ for (const MapInfo &L : M.second) {
+ assert(!L.Components.empty() &&
+ "Not expecting declaration with no component lists.");
+ generateInfoForComponentList(L.MapType, L.MapModifiers, L.Components,
+ CurBasePointers, CurPointers, CurSizes,
+ CurTypes, PartialStruct,
+ IsFirstComponentList, L.IsImplicit);
+ IsFirstComponentList = false;
+ }
+
+ // If there is an entry in PartialStruct it means we have a struct with
+ // individual members mapped. Emit an extra combined entry.
+ if (PartialStruct.Base.isValid())
+ emitCombinedEntry(BasePointers, Pointers, Sizes, Types, CurTypes,
+ PartialStruct);
+
+ // We need to append the results of this capture to what we already have.
+ BasePointers.append(CurBasePointers.begin(), CurBasePointers.end());
+ Pointers.append(CurPointers.begin(), CurPointers.end());
+ Sizes.append(CurSizes.begin(), CurSizes.end());
+ Types.append(CurTypes.begin(), CurTypes.end());
+ }
+ }
+
/// Emit capture info for lambdas for variables captured by reference.
void generateInfoForLambdaCaptures(
const ValueDecl *VD, llvm::Value *Arg, MapBaseValuesArrayTy &BasePointers,
@@ -8184,8 +8282,10 @@ public:
std::tuple<OMPClauseMappableExprCommon::MappableExprComponentListRef,
OpenMPMapClauseKind, ArrayRef<OpenMPMapModifierKind>, bool>;
SmallVector<MapData, 4> DeclComponentLists;
- // FIXME: MSVC 2013 seems to require this-> to find member CurDir.
- for (const auto *C : this->CurDir.getClausesOfKind<OMPMapClause>()) {
+ assert(CurDir.is<const OMPExecutableDirective *>() &&
+ "Expect a executable directive");
+ const auto *CurExecDir = CurDir.get<const OMPExecutableDirective *>();
+ for (const auto *C : CurExecDir->getClausesOfKind<OMPMapClause>()) {
for (const auto &L : C->decl_component_lists(VD)) {
assert(L.first == VD &&
"We got information for the wrong declaration??");
@@ -8333,9 +8433,12 @@ public:
MapValuesArrayTy &Pointers,
MapValuesArrayTy &Sizes,
MapFlagsArrayTy &Types) const {
+ assert(CurDir.is<const OMPExecutableDirective *>() &&
+ "Expect a executable directive");
+ const auto *CurExecDir = CurDir.get<const OMPExecutableDirective *>();
// Map other list items in the map clause which are not captured variables
// but "declare target link" global variables.
- for (const auto *C : this->CurDir.getClausesOfKind<OMPMapClause>()) {
+ for (const auto *C : CurExecDir->getClausesOfKind<OMPMapClause>()) {
for (const auto &L : C->component_lists()) {
if (!L.first)
continue;
@@ -8472,9 +8575,9 @@ emitOffloadingArrays(CodeGenFunction &CGF,
}
llvm::APInt PointerNumAP(32, Info.NumberOfPtrs, /*isSigned=*/true);
- QualType PointerArrayType =
- Ctx.getConstantArrayType(Ctx.VoidPtrTy, PointerNumAP, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
+ QualType PointerArrayType = Ctx.getConstantArrayType(
+ Ctx.VoidPtrTy, PointerNumAP, nullptr, ArrayType::Normal,
+ /*IndexTypeQuals=*/0);
Info.BasePointersArray =
CGF.CreateMemTemp(PointerArrayType, ".offload_baseptrs").getPointer();
@@ -8487,9 +8590,9 @@ emitOffloadingArrays(CodeGenFunction &CGF,
QualType Int64Ty =
Ctx.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
if (hasRuntimeEvaluationCaptureSize) {
- QualType SizeArrayType =
- Ctx.getConstantArrayType(Int64Ty, PointerNumAP, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
+ QualType SizeArrayType = Ctx.getConstantArrayType(
+ Int64Ty, PointerNumAP, nullptr, ArrayType::Normal,
+ /*IndexTypeQuals=*/0);
Info.SizesArray =
CGF.CreateMemTemp(SizeArrayType, ".offload_sizes").getPointer();
} else {
@@ -8562,6 +8665,7 @@ emitOffloadingArrays(CodeGenFunction &CGF,
}
}
}
+
/// Emit the arguments to be passed to the runtime library based on the
/// arrays of pointers, sizes and map types.
static void emitOffloadingArraysArgument(
@@ -8677,12 +8781,16 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) {
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_target_update:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_requires:
case OMPD_unknown:
llvm_unreachable("Unexpected directive.");
@@ -8692,10 +8800,343 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) {
return nullptr;
}
+/// Emit the user-defined mapper function. The code generation follows the
+/// pattern in the example below.
+/// \code
+/// void .omp_mapper.<type_name>.<mapper_id>.(void *rt_mapper_handle,
+/// void *base, void *begin,
+/// int64_t size, int64_t type) {
+/// // Allocate space for an array section first.
+/// if (size > 1 && !maptype.IsDelete)
+/// __tgt_push_mapper_component(rt_mapper_handle, base, begin,
+/// size*sizeof(Ty), clearToFrom(type));
+/// // Map members.
+/// for (unsigned i = 0; i < size; i++) {
+/// // For each component specified by this mapper:
+/// for (auto c : all_components) {
+/// if (c.hasMapper())
+/// (*c.Mapper())(rt_mapper_handle, c.arg_base, c.arg_begin, c.arg_size,
+/// c.arg_type);
+/// else
+/// __tgt_push_mapper_component(rt_mapper_handle, c.arg_base,
+/// c.arg_begin, c.arg_size, c.arg_type);
+/// }
+/// }
+/// // Delete the array section.
+/// if (size > 1 && maptype.IsDelete)
+/// __tgt_push_mapper_component(rt_mapper_handle, base, begin,
+/// size*sizeof(Ty), clearToFrom(type));
+/// }
+/// \endcode
+void CGOpenMPRuntime::emitUserDefinedMapper(const OMPDeclareMapperDecl *D,
+ CodeGenFunction *CGF) {
+ if (UDMMap.count(D) > 0)
+ return;
+ ASTContext &C = CGM.getContext();
+ QualType Ty = D->getType();
+ QualType PtrTy = C.getPointerType(Ty).withRestrict();
+ QualType Int64Ty = C.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/true);
+ auto *MapperVarDecl =
+ cast<VarDecl>(cast<DeclRefExpr>(D->getMapperVarRef())->getDecl());
+ SourceLocation Loc = D->getLocation();
+ CharUnits ElementSize = C.getTypeSizeInChars(Ty);
+
+ // Prepare mapper function arguments and attributes.
+ ImplicitParamDecl HandleArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ C.VoidPtrTy, ImplicitParamDecl::Other);
+ ImplicitParamDecl BaseArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, C.VoidPtrTy,
+ ImplicitParamDecl::Other);
+ ImplicitParamDecl BeginArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr,
+ C.VoidPtrTy, ImplicitParamDecl::Other);
+ ImplicitParamDecl SizeArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, Int64Ty,
+ ImplicitParamDecl::Other);
+ ImplicitParamDecl TypeArg(C, /*DC=*/nullptr, Loc, /*Id=*/nullptr, Int64Ty,
+ ImplicitParamDecl::Other);
+ FunctionArgList Args;
+ Args.push_back(&HandleArg);
+ Args.push_back(&BaseArg);
+ Args.push_back(&BeginArg);
+ Args.push_back(&SizeArg);
+ Args.push_back(&TypeArg);
+ const CGFunctionInfo &FnInfo =
+ CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
+ llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
+ SmallString<64> TyStr;
+ llvm::raw_svector_ostream Out(TyStr);
+ CGM.getCXXABI().getMangleContext().mangleTypeName(Ty, Out);
+ std::string Name = getName({"omp_mapper", TyStr, D->getName()});
+ auto *Fn = llvm::Function::Create(FnTy, llvm::GlobalValue::InternalLinkage,
+ Name, &CGM.getModule());
+ CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FnInfo);
+ Fn->removeFnAttr(llvm::Attribute::OptimizeNone);
+ // Start the mapper function code generation.
+ CodeGenFunction MapperCGF(CGM);
+ MapperCGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc);
+ // Compute the starting and end addreses of array elements.
+ llvm::Value *Size = MapperCGF.EmitLoadOfScalar(
+ MapperCGF.GetAddrOfLocalVar(&SizeArg), /*Volatile=*/false,
+ C.getPointerType(Int64Ty), Loc);
+ llvm::Value *PtrBegin = MapperCGF.Builder.CreateBitCast(
+ MapperCGF.GetAddrOfLocalVar(&BeginArg).getPointer(),
+ CGM.getTypes().ConvertTypeForMem(C.getPointerType(PtrTy)));
+ llvm::Value *PtrEnd = MapperCGF.Builder.CreateGEP(PtrBegin, Size);
+ llvm::Value *MapType = MapperCGF.EmitLoadOfScalar(
+ MapperCGF.GetAddrOfLocalVar(&TypeArg), /*Volatile=*/false,
+ C.getPointerType(Int64Ty), Loc);
+ // Prepare common arguments for array initiation and deletion.
+ llvm::Value *Handle = MapperCGF.EmitLoadOfScalar(
+ MapperCGF.GetAddrOfLocalVar(&HandleArg),
+ /*Volatile=*/false, C.getPointerType(C.VoidPtrTy), Loc);
+ llvm::Value *BaseIn = MapperCGF.EmitLoadOfScalar(
+ MapperCGF.GetAddrOfLocalVar(&BaseArg),
+ /*Volatile=*/false, C.getPointerType(C.VoidPtrTy), Loc);
+ llvm::Value *BeginIn = MapperCGF.EmitLoadOfScalar(
+ MapperCGF.GetAddrOfLocalVar(&BeginArg),
+ /*Volatile=*/false, C.getPointerType(C.VoidPtrTy), Loc);
+
+ // Emit array initiation if this is an array section and \p MapType indicates
+ // that memory allocation is required.
+ llvm::BasicBlock *HeadBB = MapperCGF.createBasicBlock("omp.arraymap.head");
+ emitUDMapperArrayInitOrDel(MapperCGF, Handle, BaseIn, BeginIn, Size, MapType,
+ ElementSize, HeadBB, /*IsInit=*/true);
+
+ // Emit a for loop to iterate through SizeArg of elements and map all of them.
+
+ // Emit the loop header block.
+ MapperCGF.EmitBlock(HeadBB);
+ llvm::BasicBlock *BodyBB = MapperCGF.createBasicBlock("omp.arraymap.body");
+ llvm::BasicBlock *DoneBB = MapperCGF.createBasicBlock("omp.done");
+ // Evaluate whether the initial condition is satisfied.
+ llvm::Value *IsEmpty =
+ MapperCGF.Builder.CreateICmpEQ(PtrBegin, PtrEnd, "omp.arraymap.isempty");
+ MapperCGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
+ llvm::BasicBlock *EntryBB = MapperCGF.Builder.GetInsertBlock();
+
+ // Emit the loop body block.
+ MapperCGF.EmitBlock(BodyBB);
+ llvm::PHINode *PtrPHI = MapperCGF.Builder.CreatePHI(
+ PtrBegin->getType(), 2, "omp.arraymap.ptrcurrent");
+ PtrPHI->addIncoming(PtrBegin, EntryBB);
+ Address PtrCurrent =
+ Address(PtrPHI, MapperCGF.GetAddrOfLocalVar(&BeginArg)
+ .getAlignment()
+ .alignmentOfArrayElement(ElementSize));
+ // Privatize the declared variable of mapper to be the current array element.
+ CodeGenFunction::OMPPrivateScope Scope(MapperCGF);
+ Scope.addPrivate(MapperVarDecl, [&MapperCGF, PtrCurrent, PtrTy]() {
+ return MapperCGF
+ .EmitLoadOfPointerLValue(PtrCurrent, PtrTy->castAs<PointerType>())
+ .getAddress();
+ });
+ (void)Scope.Privatize();
+
+ // Get map clause information. Fill up the arrays with all mapped variables.
+ MappableExprsHandler::MapBaseValuesArrayTy BasePointers;
+ MappableExprsHandler::MapValuesArrayTy Pointers;
+ MappableExprsHandler::MapValuesArrayTy Sizes;
+ MappableExprsHandler::MapFlagsArrayTy MapTypes;
+ MappableExprsHandler MEHandler(*D, MapperCGF);
+ MEHandler.generateAllInfoForMapper(BasePointers, Pointers, Sizes, MapTypes);
+
+ // Call the runtime API __tgt_mapper_num_components to get the number of
+ // pre-existing components.
+ llvm::Value *OffloadingArgs[] = {Handle};
+ llvm::Value *PreviousSize = MapperCGF.EmitRuntimeCall(
+ createRuntimeFunction(OMPRTL__tgt_mapper_num_components), OffloadingArgs);
+ llvm::Value *ShiftedPreviousSize = MapperCGF.Builder.CreateShl(
+ PreviousSize,
+ MapperCGF.Builder.getInt64(MappableExprsHandler::getFlagMemberOffset()));
+
+ // Fill up the runtime mapper handle for all components.
+ for (unsigned I = 0; I < BasePointers.size(); ++I) {
+ llvm::Value *CurBaseArg = MapperCGF.Builder.CreateBitCast(
+ *BasePointers[I], CGM.getTypes().ConvertTypeForMem(C.VoidPtrTy));
+ llvm::Value *CurBeginArg = MapperCGF.Builder.CreateBitCast(
+ Pointers[I], CGM.getTypes().ConvertTypeForMem(C.VoidPtrTy));
+ llvm::Value *CurSizeArg = Sizes[I];
+
+ // Extract the MEMBER_OF field from the map type.
+ llvm::BasicBlock *MemberBB = MapperCGF.createBasicBlock("omp.member");
+ MapperCGF.EmitBlock(MemberBB);
+ llvm::Value *OriMapType = MapperCGF.Builder.getInt64(MapTypes[I]);
+ llvm::Value *Member = MapperCGF.Builder.CreateAnd(
+ OriMapType,
+ MapperCGF.Builder.getInt64(MappableExprsHandler::OMP_MAP_MEMBER_OF));
+ llvm::BasicBlock *MemberCombineBB =
+ MapperCGF.createBasicBlock("omp.member.combine");
+ llvm::BasicBlock *TypeBB = MapperCGF.createBasicBlock("omp.type");
+ llvm::Value *IsMember = MapperCGF.Builder.CreateIsNull(Member);
+ MapperCGF.Builder.CreateCondBr(IsMember, TypeBB, MemberCombineBB);
+ // Add the number of pre-existing components to the MEMBER_OF field if it
+ // is valid.
+ MapperCGF.EmitBlock(MemberCombineBB);
+ llvm::Value *CombinedMember =
+ MapperCGF.Builder.CreateNUWAdd(OriMapType, ShiftedPreviousSize);
+ // Do nothing if it is not a member of previous components.
+ MapperCGF.EmitBlock(TypeBB);
+ llvm::PHINode *MemberMapType =
+ MapperCGF.Builder.CreatePHI(CGM.Int64Ty, 4, "omp.membermaptype");
+ MemberMapType->addIncoming(OriMapType, MemberBB);
+ MemberMapType->addIncoming(CombinedMember, MemberCombineBB);
+
+ // Combine the map type inherited from user-defined mapper with that
+ // specified in the program. According to the OMP_MAP_TO and OMP_MAP_FROM
+ // bits of the \a MapType, which is the input argument of the mapper
+ // function, the following code will set the OMP_MAP_TO and OMP_MAP_FROM
+ // bits of MemberMapType.
+ // [OpenMP 5.0], 1.2.6. map-type decay.
+ // | alloc | to | from | tofrom | release | delete
+ // ----------------------------------------------------------
+ // alloc | alloc | alloc | alloc | alloc | release | delete
+ // to | alloc | to | alloc | to | release | delete
+ // from | alloc | alloc | from | from | release | delete
+ // tofrom | alloc | to | from | tofrom | release | delete
+ llvm::Value *LeftToFrom = MapperCGF.Builder.CreateAnd(
+ MapType,
+ MapperCGF.Builder.getInt64(MappableExprsHandler::OMP_MAP_TO |
+ MappableExprsHandler::OMP_MAP_FROM));
+ llvm::BasicBlock *AllocBB = MapperCGF.createBasicBlock("omp.type.alloc");
+ llvm::BasicBlock *AllocElseBB =
+ MapperCGF.createBasicBlock("omp.type.alloc.else");
+ llvm::BasicBlock *ToBB = MapperCGF.createBasicBlock("omp.type.to");
+ llvm::BasicBlock *ToElseBB = MapperCGF.createBasicBlock("omp.type.to.else");
+ llvm::BasicBlock *FromBB = MapperCGF.createBasicBlock("omp.type.from");
+ llvm::BasicBlock *EndBB = MapperCGF.createBasicBlock("omp.type.end");
+ llvm::Value *IsAlloc = MapperCGF.Builder.CreateIsNull(LeftToFrom);
+ MapperCGF.Builder.CreateCondBr(IsAlloc, AllocBB, AllocElseBB);
+ // In case of alloc, clear OMP_MAP_TO and OMP_MAP_FROM.
+ MapperCGF.EmitBlock(AllocBB);
+ llvm::Value *AllocMapType = MapperCGF.Builder.CreateAnd(
+ MemberMapType,
+ MapperCGF.Builder.getInt64(~(MappableExprsHandler::OMP_MAP_TO |
+ MappableExprsHandler::OMP_MAP_FROM)));
+ MapperCGF.Builder.CreateBr(EndBB);
+ MapperCGF.EmitBlock(AllocElseBB);
+ llvm::Value *IsTo = MapperCGF.Builder.CreateICmpEQ(
+ LeftToFrom,
+ MapperCGF.Builder.getInt64(MappableExprsHandler::OMP_MAP_TO));
+ MapperCGF.Builder.CreateCondBr(IsTo, ToBB, ToElseBB);
+ // In case of to, clear OMP_MAP_FROM.
+ MapperCGF.EmitBlock(ToBB);
+ llvm::Value *ToMapType = MapperCGF.Builder.CreateAnd(
+ MemberMapType,
+ MapperCGF.Builder.getInt64(~MappableExprsHandler::OMP_MAP_FROM));
+ MapperCGF.Builder.CreateBr(EndBB);
+ MapperCGF.EmitBlock(ToElseBB);
+ llvm::Value *IsFrom = MapperCGF.Builder.CreateICmpEQ(
+ LeftToFrom,
+ MapperCGF.Builder.getInt64(MappableExprsHandler::OMP_MAP_FROM));
+ MapperCGF.Builder.CreateCondBr(IsFrom, FromBB, EndBB);
+ // In case of from, clear OMP_MAP_TO.
+ MapperCGF.EmitBlock(FromBB);
+ llvm::Value *FromMapType = MapperCGF.Builder.CreateAnd(
+ MemberMapType,
+ MapperCGF.Builder.getInt64(~MappableExprsHandler::OMP_MAP_TO));
+ // In case of tofrom, do nothing.
+ MapperCGF.EmitBlock(EndBB);
+ llvm::PHINode *CurMapType =
+ MapperCGF.Builder.CreatePHI(CGM.Int64Ty, 4, "omp.maptype");
+ CurMapType->addIncoming(AllocMapType, AllocBB);
+ CurMapType->addIncoming(ToMapType, ToBB);
+ CurMapType->addIncoming(FromMapType, FromBB);
+ CurMapType->addIncoming(MemberMapType, ToElseBB);
+
+ // TODO: call the corresponding mapper function if a user-defined mapper is
+ // associated with this map clause.
+ // Call the runtime API __tgt_push_mapper_component to fill up the runtime
+ // data structure.
+ llvm::Value *OffloadingArgs[] = {Handle, CurBaseArg, CurBeginArg,
+ CurSizeArg, CurMapType};
+ MapperCGF.EmitRuntimeCall(
+ createRuntimeFunction(OMPRTL__tgt_push_mapper_component),
+ OffloadingArgs);
+ }
+
+ // Update the pointer to point to the next element that needs to be mapped,
+ // and check whether we have mapped all elements.
+ llvm::Value *PtrNext = MapperCGF.Builder.CreateConstGEP1_32(
+ PtrPHI, /*Idx0=*/1, "omp.arraymap.next");
+ PtrPHI->addIncoming(PtrNext, BodyBB);
+ llvm::Value *IsDone =
+ MapperCGF.Builder.CreateICmpEQ(PtrNext, PtrEnd, "omp.arraymap.isdone");
+ llvm::BasicBlock *ExitBB = MapperCGF.createBasicBlock("omp.arraymap.exit");
+ MapperCGF.Builder.CreateCondBr(IsDone, ExitBB, BodyBB);
+
+ MapperCGF.EmitBlock(ExitBB);
+ // Emit array deletion if this is an array section and \p MapType indicates
+ // that deletion is required.
+ emitUDMapperArrayInitOrDel(MapperCGF, Handle, BaseIn, BeginIn, Size, MapType,
+ ElementSize, DoneBB, /*IsInit=*/false);
+
+ // Emit the function exit block.
+ MapperCGF.EmitBlock(DoneBB, /*IsFinished=*/true);
+ MapperCGF.FinishFunction();
+ UDMMap.try_emplace(D, Fn);
+ if (CGF) {
+ auto &Decls = FunctionUDMMap.FindAndConstruct(CGF->CurFn);
+ Decls.second.push_back(D);
+ }
+}
+
+/// Emit the array initialization or deletion portion for user-defined mapper
+/// code generation. First, it evaluates whether an array section is mapped and
+/// whether the \a MapType instructs to delete this section. If \a IsInit is
+/// true, and \a MapType indicates to not delete this array, array
+/// initialization code is generated. If \a IsInit is false, and \a MapType
+/// indicates to not this array, array deletion code is generated.
+void CGOpenMPRuntime::emitUDMapperArrayInitOrDel(
+ CodeGenFunction &MapperCGF, llvm::Value *Handle, llvm::Value *Base,
+ llvm::Value *Begin, llvm::Value *Size, llvm::Value *MapType,
+ CharUnits ElementSize, llvm::BasicBlock *ExitBB, bool IsInit) {
+ StringRef Prefix = IsInit ? ".init" : ".del";
+
+ // Evaluate if this is an array section.
+ llvm::BasicBlock *IsDeleteBB =
+ MapperCGF.createBasicBlock("omp.array" + Prefix + ".evaldelete");
+ llvm::BasicBlock *BodyBB = MapperCGF.createBasicBlock("omp.array" + Prefix);
+ llvm::Value *IsArray = MapperCGF.Builder.CreateICmpSGE(
+ Size, MapperCGF.Builder.getInt64(1), "omp.arrayinit.isarray");
+ MapperCGF.Builder.CreateCondBr(IsArray, IsDeleteBB, ExitBB);
+
+ // Evaluate if we are going to delete this section.
+ MapperCGF.EmitBlock(IsDeleteBB);
+ llvm::Value *DeleteBit = MapperCGF.Builder.CreateAnd(
+ MapType,
+ MapperCGF.Builder.getInt64(MappableExprsHandler::OMP_MAP_DELETE));
+ llvm::Value *DeleteCond;
+ if (IsInit) {
+ DeleteCond = MapperCGF.Builder.CreateIsNull(
+ DeleteBit, "omp.array" + Prefix + ".delete");
+ } else {
+ DeleteCond = MapperCGF.Builder.CreateIsNotNull(
+ DeleteBit, "omp.array" + Prefix + ".delete");
+ }
+ MapperCGF.Builder.CreateCondBr(DeleteCond, BodyBB, ExitBB);
+
+ MapperCGF.EmitBlock(BodyBB);
+ // Get the array size by multiplying element size and element number (i.e., \p
+ // Size).
+ llvm::Value *ArraySize = MapperCGF.Builder.CreateNUWMul(
+ Size, MapperCGF.Builder.getInt64(ElementSize.getQuantity()));
+ // Remove OMP_MAP_TO and OMP_MAP_FROM from the map type, so that it achieves
+ // memory allocation/deletion purpose only.
+ llvm::Value *MapTypeArg = MapperCGF.Builder.CreateAnd(
+ MapType,
+ MapperCGF.Builder.getInt64(~(MappableExprsHandler::OMP_MAP_TO |
+ MappableExprsHandler::OMP_MAP_FROM)));
+ // Call the runtime API __tgt_push_mapper_component to fill up the runtime
+ // data structure.
+ llvm::Value *OffloadingArgs[] = {Handle, Base, Begin, ArraySize, MapTypeArg};
+ MapperCGF.EmitRuntimeCall(
+ createRuntimeFunction(OMPRTL__tgt_push_mapper_component), OffloadingArgs);
+}
+
void CGOpenMPRuntime::emitTargetNumIterationsCall(
- CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *Device,
- const llvm::function_ref<llvm::Value *(
- CodeGenFunction &CGF, const OMPLoopDirective &D)> &SizeEmitter) {
+ CodeGenFunction &CGF, const OMPExecutableDirective &D,
+ llvm::Value *DeviceID,
+ llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
+ const OMPLoopDirective &D)>
+ SizeEmitter) {
OpenMPDirectiveKind Kind = D.getDirectiveKind();
const OMPExecutableDirective *TD = &D;
// Get nested teams distribute kind directive, if any.
@@ -8704,30 +9145,24 @@ void CGOpenMPRuntime::emitTargetNumIterationsCall(
if (!TD)
return;
const auto *LD = cast<OMPLoopDirective>(TD);
- auto &&CodeGen = [LD, &Device, &SizeEmitter, this](CodeGenFunction &CGF,
+ auto &&CodeGen = [LD, DeviceID, SizeEmitter, this](CodeGenFunction &CGF,
PrePostActionTy &) {
- llvm::Value *NumIterations = SizeEmitter(CGF, *LD);
-
- // Emit device ID if any.
- llvm::Value *DeviceID;
- if (Device)
- DeviceID = CGF.Builder.CreateIntCast(CGF.EmitScalarExpr(Device),
- CGF.Int64Ty, /*isSigned=*/true);
- else
- DeviceID = CGF.Builder.getInt64(OMP_DEVICEID_UNDEF);
-
- llvm::Value *Args[] = {DeviceID, NumIterations};
- CGF.EmitRuntimeCall(
- createRuntimeFunction(OMPRTL__kmpc_push_target_tripcount), Args);
+ if (llvm::Value *NumIterations = SizeEmitter(CGF, *LD)) {
+ llvm::Value *Args[] = {DeviceID, NumIterations};
+ CGF.EmitRuntimeCall(
+ createRuntimeFunction(OMPRTL__kmpc_push_target_tripcount), Args);
+ }
};
emitInlinedDirective(CGF, OMPD_unknown, CodeGen);
}
-void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF,
- const OMPExecutableDirective &D,
- llvm::Function *OutlinedFn,
- llvm::Value *OutlinedFnID,
- const Expr *IfCond, const Expr *Device) {
+void CGOpenMPRuntime::emitTargetCall(
+ CodeGenFunction &CGF, const OMPExecutableDirective &D,
+ llvm::Function *OutlinedFn, llvm::Value *OutlinedFnID, const Expr *IfCond,
+ const Expr *Device,
+ llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
+ const OMPLoopDirective &D)>
+ SizeEmitter) {
if (!CGF.HaveInsertPoint())
return;
@@ -8746,8 +9181,8 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF,
llvm::Value *MapTypesArray = nullptr;
// Fill up the pointer arrays and transfer execution to the device.
auto &&ThenGen = [this, Device, OutlinedFn, OutlinedFnID, &D, &InputInfo,
- &MapTypesArray, &CS, RequiresOuterTask,
- &CapturedVars](CodeGenFunction &CGF, PrePostActionTy &) {
+ &MapTypesArray, &CS, RequiresOuterTask, &CapturedVars,
+ SizeEmitter](CodeGenFunction &CGF, PrePostActionTy &) {
// On top of the arrays that were filled up, the target offloading call
// takes as arguments the device id as well as the host pointer. The host
// pointer is used by the runtime library to identify the current target
@@ -8779,6 +9214,9 @@ void CGOpenMPRuntime::emitTargetCall(CodeGenFunction &CGF,
llvm::Value *NumTeams = emitNumTeamsForTargetDirective(CGF, D);
llvm::Value *NumThreads = emitNumThreadsForTargetDirective(CGF, D);
+ // Emit tripcount for the target loop-based directive.
+ emitTargetNumIterationsCall(CGF, D, DeviceID, SizeEmitter);
+
bool HasNowait = D.hasClausesOfKind<OMPNowaitClause>();
// The target region is an outlined function launched by the runtime
// via calls __tgt_target() or __tgt_target_teams().
@@ -9103,12 +9541,16 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S,
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_target_update:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_requires:
case OMPD_unknown:
llvm_unreachable("Unknown target directive for OpenMP device codegen.");
@@ -9137,14 +9579,28 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S,
bool CGOpenMPRuntime::emitTargetFunctions(GlobalDecl GD) {
// If emitting code for the host, we do not process FD here. Instead we do
// the normal code generation.
- if (!CGM.getLangOpts().OpenMPIsDevice)
+ if (!CGM.getLangOpts().OpenMPIsDevice) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(GD.getDecl())) {
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(FD);
+ // Do not emit device_type(nohost) functions for the host.
+ if (DevTy && *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
+ return true;
+ }
return false;
+ }
const ValueDecl *VD = cast<ValueDecl>(GD.getDecl());
StringRef Name = CGM.getMangledName(GD);
// Try to detect target regions in the function.
- if (const auto *FD = dyn_cast<FunctionDecl>(VD))
+ if (const auto *FD = dyn_cast<FunctionDecl>(VD)) {
scanForTargetRegionsFunctions(FD->getBody(), Name);
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(FD);
+ // Do not emit device_type(nohost) functions for the host.
+ if (DevTy && *DevTy == OMPDeclareTargetDeclAttr::DT_Host)
+ return true;
+ }
// Do not to emit function if it is not marked as declare target.
return !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) &&
@@ -9221,6 +9677,9 @@ CGOpenMPRuntime::registerTargetFirstprivateCopy(CodeGenFunction &CGF,
void CGOpenMPRuntime::registerTargetGlobalVariable(const VarDecl *VD,
llvm::Constant *Addr) {
+ if (CGM.getLangOpts().OMPTargetTriples.empty() &&
+ !CGM.getLangOpts().OpenMPIsDevice)
+ return;
llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (!Res) {
@@ -9433,17 +9892,6 @@ llvm::Function *CGOpenMPRuntime::emitRequiresDirectiveRegFun() {
return RequiresRegFn;
}
-llvm::Function *CGOpenMPRuntime::emitRegistrationFunction() {
- // If we have offloading in the current module, we need to emit the entries
- // now and register the offloading descriptor.
- createOffloadEntriesAndInfoMetadata();
-
- // Create and register the offloading binary descriptors. This is the main
- // entity that captures all the information about offloading in the current
- // compilation unit.
- return createOffloadingBinaryDescriptorRegistration();
-}
-
void CGOpenMPRuntime::emitTeamsCall(CodeGenFunction &CGF,
const OMPExecutableDirective &D,
SourceLocation Loc,
@@ -9711,12 +10159,16 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall(
case OMPD_teams_distribute_parallel_for:
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_target:
case OMPD_target_simd:
case OMPD_target_teams_distribute:
@@ -10377,7 +10829,7 @@ void CGOpenMPRuntime::emitDoacrossInit(CodeGenFunction &CGF,
}
llvm::APInt Size(/*numBits=*/32, NumIterations.size());
QualType ArrayTy =
- C.getConstantArrayType(KmpDimTy, Size, ArrayType::Normal, 0);
+ C.getConstantArrayType(KmpDimTy, Size, nullptr, ArrayType::Normal, 0);
Address DimsAddr = CGF.CreateMemTemp(ArrayTy, "dims");
CGF.EmitNullInitialization(DimsAddr, ArrayTy);
@@ -10428,7 +10880,7 @@ void CGOpenMPRuntime::emitDoacrossOrdered(CodeGenFunction &CGF,
CGM.getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
llvm::APInt Size(/*numBits=*/32, C->getNumLoops());
QualType ArrayTy = CGM.getContext().getConstantArrayType(
- Int64Ty, Size, ArrayType::Normal, 0);
+ Int64Ty, Size, nullptr, ArrayType::Normal, 0);
Address CntAddr = CGF.CreateMemTemp(ArrayTy, ".cnt.addr");
for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) {
const Expr *CounterVal = C->getLoopData(I);
@@ -10566,6 +11018,131 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF,
return Address(Addr, Align);
}
+/// Checks current context and returns true if it matches the context selector.
+template <OMPDeclareVariantAttr::CtxSelectorSetType CtxSet,
+ OMPDeclareVariantAttr::CtxSelectorType Ctx>
+static bool checkContext(const OMPDeclareVariantAttr *A) {
+ assert(CtxSet != OMPDeclareVariantAttr::CtxSetUnknown &&
+ Ctx != OMPDeclareVariantAttr::CtxUnknown &&
+ "Unknown context selector or context selector set.");
+ return false;
+}
+
+/// Checks for implementation={vendor(<vendor>)} context selector.
+/// \returns true iff <vendor>="llvm", false otherwise.
+template <>
+bool checkContext<OMPDeclareVariantAttr::CtxSetImplementation,
+ OMPDeclareVariantAttr::CtxVendor>(
+ const OMPDeclareVariantAttr *A) {
+ return llvm::all_of(A->implVendors(),
+ [](StringRef S) { return !S.compare_lower("llvm"); });
+}
+
+static bool greaterCtxScore(ASTContext &Ctx, const Expr *LHS, const Expr *RHS) {
+ // If both scores are unknown, choose the very first one.
+ if (!LHS && !RHS)
+ return true;
+ // If only one is known, return this one.
+ if (LHS && !RHS)
+ return true;
+ if (!LHS && RHS)
+ return false;
+ llvm::APSInt LHSVal = LHS->EvaluateKnownConstInt(Ctx);
+ llvm::APSInt RHSVal = RHS->EvaluateKnownConstInt(Ctx);
+ return llvm::APSInt::compareValues(LHSVal, RHSVal) >= 0;
+}
+
+namespace {
+/// Comparator for the priority queue for context selector.
+class OMPDeclareVariantAttrComparer
+ : public std::greater<const OMPDeclareVariantAttr *> {
+private:
+ ASTContext &Ctx;
+
+public:
+ OMPDeclareVariantAttrComparer(ASTContext &Ctx) : Ctx(Ctx) {}
+ bool operator()(const OMPDeclareVariantAttr *LHS,
+ const OMPDeclareVariantAttr *RHS) const {
+ const Expr *LHSExpr = nullptr;
+ const Expr *RHSExpr = nullptr;
+ if (LHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified)
+ LHSExpr = LHS->getScore();
+ if (RHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified)
+ RHSExpr = RHS->getScore();
+ return greaterCtxScore(Ctx, LHSExpr, RHSExpr);
+ }
+};
+} // anonymous namespace
+
+/// Finds the variant function that matches current context with its context
+/// selector.
+static const FunctionDecl *getDeclareVariantFunction(ASTContext &Ctx,
+ const FunctionDecl *FD) {
+ if (!FD->hasAttrs() || !FD->hasAttr<OMPDeclareVariantAttr>())
+ return FD;
+ // Iterate through all DeclareVariant attributes and check context selectors.
+ auto &&Comparer = [&Ctx](const OMPDeclareVariantAttr *LHS,
+ const OMPDeclareVariantAttr *RHS) {
+ const Expr *LHSExpr = nullptr;
+ const Expr *RHSExpr = nullptr;
+ if (LHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified)
+ LHSExpr = LHS->getScore();
+ if (RHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified)
+ RHSExpr = RHS->getScore();
+ return greaterCtxScore(Ctx, LHSExpr, RHSExpr);
+ };
+ const OMPDeclareVariantAttr *TopMostAttr = nullptr;
+ for (const auto *A : FD->specific_attrs<OMPDeclareVariantAttr>()) {
+ const OMPDeclareVariantAttr *SelectedAttr = nullptr;
+ switch (A->getCtxSelectorSet()) {
+ case OMPDeclareVariantAttr::CtxSetImplementation:
+ switch (A->getCtxSelector()) {
+ case OMPDeclareVariantAttr::CtxVendor:
+ if (checkContext<OMPDeclareVariantAttr::CtxSetImplementation,
+ OMPDeclareVariantAttr::CtxVendor>(A))
+ SelectedAttr = A;
+ break;
+ case OMPDeclareVariantAttr::CtxUnknown:
+ llvm_unreachable(
+ "Unknown context selector in implementation selector set.");
+ }
+ break;
+ case OMPDeclareVariantAttr::CtxSetUnknown:
+ llvm_unreachable("Unknown context selector set.");
+ }
+ // If the attribute matches the context, find the attribute with the highest
+ // score.
+ if (SelectedAttr && (!TopMostAttr || !Comparer(TopMostAttr, SelectedAttr)))
+ TopMostAttr = SelectedAttr;
+ }
+ if (!TopMostAttr)
+ return FD;
+ return cast<FunctionDecl>(
+ cast<DeclRefExpr>(TopMostAttr->getVariantFuncRef()->IgnoreParenImpCasts())
+ ->getDecl());
+}
+
+bool CGOpenMPRuntime::emitDeclareVariant(GlobalDecl GD, bool IsForDefinition) {
+ const auto *D = cast<FunctionDecl>(GD.getDecl());
+ // If the original function is defined already, use its definition.
+ StringRef MangledName = CGM.getMangledName(GD);
+ llvm::GlobalValue *Orig = CGM.GetGlobalValue(MangledName);
+ if (Orig && !Orig->isDeclaration())
+ return false;
+ const FunctionDecl *NewFD = getDeclareVariantFunction(CGM.getContext(), D);
+ // Emit original function if it does not have declare variant attribute or the
+ // context does not match.
+ if (NewFD == D)
+ return false;
+ GlobalDecl NewGD = GD.getWithDecl(NewFD);
+ if (tryEmitDeclareVariant(NewGD, GD, Orig, IsForDefinition)) {
+ DeferredVariantFunction.erase(D);
+ return true;
+ }
+ DeferredVariantFunction.insert(std::make_pair(D, std::make_pair(NewGD, GD)));
+ return true;
+}
+
llvm::Function *CGOpenMPSIMDRuntime::emitParallelOutlinedFunction(
const OMPExecutableDirective &D, const VarDecl *ThreadIDVar,
OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) {
@@ -10786,12 +11363,13 @@ void CGOpenMPSIMDRuntime::emitTargetOutlinedFunction(
llvm_unreachable("Not supported in SIMD-only mode");
}
-void CGOpenMPSIMDRuntime::emitTargetCall(CodeGenFunction &CGF,
- const OMPExecutableDirective &D,
- llvm::Function *OutlinedFn,
- llvm::Value *OutlinedFnID,
- const Expr *IfCond,
- const Expr *Device) {
+void CGOpenMPSIMDRuntime::emitTargetCall(
+ CodeGenFunction &CGF, const OMPExecutableDirective &D,
+ llvm::Function *OutlinedFn, llvm::Value *OutlinedFnID, const Expr *IfCond,
+ const Expr *Device,
+ llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
+ const OMPLoopDirective &D)>
+ SizeEmitter) {
llvm_unreachable("Not supported in SIMD-only mode");
}
@@ -10807,10 +11385,6 @@ bool CGOpenMPSIMDRuntime::emitTargetGlobal(GlobalDecl GD) {
return false;
}
-llvm::Function *CGOpenMPSIMDRuntime::emitRegistrationFunction() {
- return nullptr;
-}
-
void CGOpenMPSIMDRuntime::emitTeamsCall(CodeGenFunction &CGF,
const OMPExecutableDirective &D,
SourceLocation Loc,
diff --git a/lib/CodeGen/CGOpenMPRuntime.h b/lib/CodeGen/CGOpenMPRuntime.h
index 3f842ce96407..bf8e0ac80909 100644
--- a/lib/CodeGen/CGOpenMPRuntime.h
+++ b/lib/CodeGen/CGOpenMPRuntime.h
@@ -15,6 +15,7 @@
#include "CGValue.h"
#include "clang/AST/DeclOpenMP.h"
+#include "clang/AST/GlobalDecl.h"
#include "clang/AST/Type.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/SourceLocation.h"
@@ -36,7 +37,6 @@ class Value;
namespace clang {
class Expr;
-class GlobalDecl;
class OMPDependClause;
class OMPExecutableDirective;
class OMPLoopDirective;
@@ -291,6 +291,17 @@ protected:
/// default location.
virtual unsigned getDefaultLocationReserved2Flags() const { return 0; }
+ /// Tries to emit declare variant function for \p OldGD from \p NewGD.
+ /// \param OrigAddr LLVM IR value for \p OldGD.
+ /// \param IsForDefinition true, if requested emission for the definition of
+ /// \p OldGD.
+ /// \returns true, was able to emit a definition function for \p OldGD, which
+ /// points to \p NewGD.
+ virtual bool tryEmitDeclareVariant(const GlobalDecl &NewGD,
+ const GlobalDecl &OldGD,
+ llvm::GlobalValue *OrigAddr,
+ bool IsForDefinition);
+
/// Returns default flags for the barriers depending on the directive, for
/// which this barier is going to be emitted.
static unsigned getDefaultFlagsForBarriers(OpenMPDirectiveKind Kind);
@@ -345,6 +356,14 @@ private:
SmallVector<const OMPDeclareReductionDecl *, 4>>
FunctionUDRMapTy;
FunctionUDRMapTy FunctionUDRMap;
+ /// Map from the user-defined mapper declaration to its corresponding
+ /// functions.
+ llvm::DenseMap<const OMPDeclareMapperDecl *, llvm::Function *> UDMMap;
+ /// Map of functions and their local user-defined mappers.
+ using FunctionUDMMapTy =
+ llvm::DenseMap<llvm::Function *,
+ SmallVector<const OMPDeclareMapperDecl *, 4>>;
+ FunctionUDMMapTy FunctionUDMMap;
/// Type kmp_critical_name, originally defined as typedef kmp_int32
/// kmp_critical_name[8];
llvm::ArrayType *KmpCriticalNameTy;
@@ -636,6 +655,12 @@ private:
/// must be emitted.
llvm::SmallDenseSet<const VarDecl *> DeferredGlobalVariables;
+ /// Mapping of the original functions to their variants and original global
+ /// decl.
+ llvm::MapVector<CanonicalDeclPtr<const FunctionDecl>,
+ std::pair<GlobalDecl, GlobalDecl>>
+ DeferredVariantFunction;
+
/// Flag for keeping track of weather a requires unified_shared_memory
/// directive is present.
bool HasRequiresUnifiedSharedMemory = false;
@@ -647,14 +672,6 @@ private:
/// Device routines are specific to the
bool HasEmittedDeclareTargetRegion = false;
- /// Creates and registers offloading binary descriptor for the current
- /// compilation unit. The function that does the registration is returned.
- llvm::Function *createOffloadingBinaryDescriptorRegistration();
-
- /// Creates all the offload entries in the current compilation unit
- /// along with the associated metadata.
- void createOffloadEntriesAndInfoMetadata();
-
/// Loads all the offload entries information from the host IR
/// metadata.
void loadOffloadInfoMetadata();
@@ -738,6 +755,14 @@ private:
llvm::Value *Ctor, llvm::Value *CopyCtor,
llvm::Value *Dtor, SourceLocation Loc);
+ /// Emit the array initialization or deletion portion for user-defined mapper
+ /// code generation.
+ void emitUDMapperArrayInitOrDel(CodeGenFunction &MapperCGF,
+ llvm::Value *Handle, llvm::Value *BasePtr,
+ llvm::Value *Ptr, llvm::Value *Size,
+ llvm::Value *MapType, CharUnits ElementSize,
+ llvm::BasicBlock *ExitBB, bool IsInit);
+
struct TaskResultTy {
llvm::Value *NewTask = nullptr;
llvm::Function *TaskEntry = nullptr;
@@ -777,6 +802,17 @@ private:
/// default.
virtual unsigned getDefaultFirstprivateAddressSpace() const { return 0; }
+ /// Emit code that pushes the trip count of loops associated with constructs
+ /// 'target teams distribute' and 'teams distribute parallel for'.
+ /// \param SizeEmitter Emits the int64 value for the number of iterations of
+ /// the associated loop.
+ void emitTargetNumIterationsCall(
+ CodeGenFunction &CGF, const OMPExecutableDirective &D,
+ llvm::Value *DeviceID,
+ llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
+ const OMPLoopDirective &D)>
+ SizeEmitter);
+
public:
explicit CGOpenMPRuntime(CodeGenModule &CGM)
: CGOpenMPRuntime(CGM, ".", ".") {}
@@ -798,6 +834,10 @@ public:
virtual std::pair<llvm::Function *, llvm::Function *>
getUserDefinedReduction(const OMPDeclareReductionDecl *D);
+ /// Emit the function for the user defined mapper construct.
+ void emitUserDefinedMapper(const OMPDeclareMapperDecl *D,
+ CodeGenFunction *CGF = nullptr);
+
/// Emits outlined function for the specified OpenMP parallel directive
/// \a D. This outlined function has type void(*)(kmp_int32 *ThreadID,
/// kmp_int32 BoundID, struct context_vars*).
@@ -1394,15 +1434,6 @@ public:
bool IsOffloadEntry,
const RegionCodeGenTy &CodeGen);
- /// Emit code that pushes the trip count of loops associated with constructs
- /// 'target teams distribute' and 'teams distribute parallel for'.
- /// \param SizeEmitter Emits the int64 value for the number of iterations of
- /// the associated loop.
- virtual void emitTargetNumIterationsCall(
- CodeGenFunction &CGF, const OMPExecutableDirective &D, const Expr *Device,
- const llvm::function_ref<llvm::Value *(
- CodeGenFunction &CGF, const OMPLoopDirective &D)> &SizeEmitter);
-
/// Emit the target offloading code associated with \a D. The emitted
/// code attempts offloading the execution to the device, an the event of
/// a failure it executes the host version outlined in \a OutlinedFn.
@@ -1413,11 +1444,15 @@ public:
/// directive, or null if no if clause is used.
/// \param Device Expression evaluated in device clause associated with the
/// target directive, or null if no device clause is used.
- virtual void emitTargetCall(CodeGenFunction &CGF,
- const OMPExecutableDirective &D,
- llvm::Function *OutlinedFn,
- llvm::Value *OutlinedFnID, const Expr *IfCond,
- const Expr *Device);
+ /// \param SizeEmitter Callback to emit number of iterations for loop-based
+ /// directives.
+ virtual void
+ emitTargetCall(CodeGenFunction &CGF, const OMPExecutableDirective &D,
+ llvm::Function *OutlinedFn, llvm::Value *OutlinedFnID,
+ const Expr *IfCond, const Expr *Device,
+ llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
+ const OMPLoopDirective &D)>
+ SizeEmitter);
/// Emit the target regions enclosed in \a GD function definition or
/// the function itself in case it is a valid device function. Returns true if
@@ -1449,10 +1484,9 @@ public:
/// requires directives was used in the current module.
llvm::Function *emitRequiresDirectiveRegFun();
- /// Creates the offloading descriptor in the event any target region
- /// was emitted in the current module and return the function that registers
- /// it.
- virtual llvm::Function *emitRegistrationFunction();
+ /// Creates all the offload entries in the current compilation unit
+ /// along with the associated metadata.
+ void createOffloadEntriesAndInfoMetadata();
/// Emits code for teams call of the \a OutlinedFn with
/// variables captured in a record which address is stored in \a
@@ -1626,6 +1660,9 @@ public:
/// Return whether the unified_shared_memory has been specified.
bool hasRequiresUnifiedSharedMemory() const;
+
+ /// Emits the definition of the declare variant function.
+ virtual bool emitDeclareVariant(GlobalDecl GD, bool IsForDefinition);
};
/// Class supports emissionof SIMD-only code.
@@ -2097,9 +2134,13 @@ public:
/// directive, or null if no if clause is used.
/// \param Device Expression evaluated in device clause associated with the
/// target directive, or null if no device clause is used.
- void emitTargetCall(CodeGenFunction &CGF, const OMPExecutableDirective &D,
- llvm::Function *OutlinedFn, llvm::Value *OutlinedFnID,
- const Expr *IfCond, const Expr *Device) override;
+ void
+ emitTargetCall(CodeGenFunction &CGF, const OMPExecutableDirective &D,
+ llvm::Function *OutlinedFn, llvm::Value *OutlinedFnID,
+ const Expr *IfCond, const Expr *Device,
+ llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
+ const OMPLoopDirective &D)>
+ SizeEmitter) override;
/// Emit the target regions enclosed in \a GD function definition or
/// the function itself in case it is a valid device function. Returns true if
@@ -2117,11 +2158,6 @@ public:
/// \param GD Global to scan.
bool emitTargetGlobal(GlobalDecl GD) override;
- /// Creates the offloading descriptor in the event any target region
- /// was emitted in the current module and return the function that registers
- /// it.
- llvm::Function *emitRegistrationFunction() override;
-
/// Emits code for teams call of the \a OutlinedFn with
/// variables captured in a record which address is stored in \a
/// CapturedStruct.
diff --git a/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp b/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
index 48dcbbf3cabd..708260429f68 100644
--- a/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
+++ b/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp
@@ -107,6 +107,10 @@ enum OpenMPRTLFunctionNVPTX {
/// Call to void __kmpc_barrier_simple_spmd(ident_t *loc, kmp_int32
/// global_tid);
OMPRTL__kmpc_barrier_simple_spmd,
+ /// Call to int32_t __kmpc_warp_active_thread_mask(void);
+ OMPRTL_NVPTX__kmpc_warp_active_thread_mask,
+ /// Call to void __kmpc_syncwarp(int32_t Mask);
+ OMPRTL_NVPTX__kmpc_syncwarp,
};
/// Pre(post)-action for different OpenMP constructs specialized for NVPTX.
@@ -276,7 +280,8 @@ static RecordDecl *buildRecordForGlobalizedVars(
}
} else {
llvm::APInt ArraySize(32, BufSize);
- Type = C.getConstantArrayType(Type, ArraySize, ArrayType::Normal, 0);
+ Type = C.getConstantArrayType(Type, ArraySize, nullptr, ArrayType::Normal,
+ 0);
Field = FieldDecl::Create(
C, GlobalizedRD, Loc, Loc, VD->getIdentifier(), Type,
C.getTrivialTypeSourceInfo(Type, SourceLocation()),
@@ -287,10 +292,11 @@ static RecordDecl *buildRecordForGlobalizedVars(
static_cast<CharUnits::QuantityType>(
GlobalMemoryAlignment)));
Field->addAttr(AlignedAttr::CreateImplicit(
- C, AlignedAttr::GNU_aligned, /*IsAlignmentExpr=*/true,
+ C, /*IsAlignmentExpr=*/true,
IntegerLiteral::Create(C, Align,
C.getIntTypeForBitwidth(32, /*Signed=*/0),
- SourceLocation())));
+ SourceLocation()),
+ {}, AttributeCommonInfo::AS_GNU, AlignedAttr::GNU_aligned));
}
GlobalizedRD->addDecl(Field);
MappedDeclsFields.try_emplace(VD, Field);
@@ -790,12 +796,16 @@ static bool hasNestedSPMDDirective(ASTContext &Ctx,
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_target_update:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_requires:
case OMPD_unknown:
llvm_unreachable("Unexpected directive.");
@@ -860,12 +870,16 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx,
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_target_update:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_requires:
case OMPD_unknown:
break;
@@ -1023,12 +1037,16 @@ static bool hasNestedLightweightDirective(ASTContext &Ctx,
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_target_update:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_requires:
case OMPD_unknown:
llvm_unreachable("Unexpected directive.");
@@ -1099,12 +1117,16 @@ static bool supportsLightweightRuntime(ASTContext &Ctx,
case OMPD_teams_distribute_parallel_for_simd:
case OMPD_target_update:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_requires:
case OMPD_unknown:
break;
@@ -1794,6 +1816,20 @@ CGOpenMPRuntimeNVPTX::createNVPTXRuntimeFunction(unsigned Function) {
->addFnAttr(llvm::Attribute::Convergent);
break;
}
+ case OMPRTL_NVPTX__kmpc_warp_active_thread_mask: {
+ // Build int32_t __kmpc_warp_active_thread_mask(void);
+ auto *FnTy =
+ llvm::FunctionType::get(CGM.Int32Ty, llvm::None, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_warp_active_thread_mask");
+ break;
+ }
+ case OMPRTL_NVPTX__kmpc_syncwarp: {
+ // Build void __kmpc_syncwarp(kmp_int32 Mask);
+ auto *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, CGM.Int32Ty, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_syncwarp");
+ break;
+ }
}
return RTLFn;
}
@@ -1871,6 +1907,19 @@ unsigned CGOpenMPRuntimeNVPTX::getDefaultLocationReserved2Flags() const {
llvm_unreachable("Unknown flags are requested.");
}
+bool CGOpenMPRuntimeNVPTX::tryEmitDeclareVariant(const GlobalDecl &NewGD,
+ const GlobalDecl &OldGD,
+ llvm::GlobalValue *OrigAddr,
+ bool IsForDefinition) {
+ // Emit the function in OldGD with the body from NewGD, if NewGD is defined.
+ auto *NewFD = cast<FunctionDecl>(NewGD.getDecl());
+ if (NewFD->isDefined()) {
+ CGM.emitOpenMPDeviceFunctionRedefinition(OldGD, NewGD, OrigAddr);
+ return true;
+ }
+ return false;
+}
+
CGOpenMPRuntimeNVPTX::CGOpenMPRuntimeNVPTX(CodeGenModule &CGM)
: CGOpenMPRuntime(CGM, "_", "$") {
if (!CGM.getLangOpts().OpenMPIsDevice)
@@ -2030,7 +2079,7 @@ llvm::Function *CGOpenMPRuntimeNVPTX::emitTeamsOutlinedFunction(
auto I = Rt.FunctionGlobalizedDecls.try_emplace(CGF.CurFn).first;
I->getSecond().GlobalRecord = GlobalizedRD;
I->getSecond().MappedParams =
- llvm::make_unique<CodeGenFunction::OMPMapVars>();
+ std::make_unique<CodeGenFunction::OMPMapVars>();
DeclToAddrMapTy &Data = I->getSecond().LocalVarData;
for (const auto &Pair : MappedDeclsFields) {
assert(Pair.getFirst()->isCanonicalDecl() &&
@@ -2414,9 +2463,8 @@ void CGOpenMPRuntimeNVPTX::emitTeamsCall(CodeGenFunction &CGF,
if (!CGF.HaveInsertPoint())
return;
- Address ZeroAddr = CGF.CreateMemTemp(
- CGF.getContext().getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1),
- /*Name*/ ".zero.addr");
+ Address ZeroAddr = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty,
+ /*Name=*/".zero.addr");
CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0));
llvm::SmallVector<llvm::Value *, 16> OutlinedFnArgs;
OutlinedFnArgs.push_back(emitThreadIDAddress(CGF, Loc).getPointer());
@@ -2445,16 +2493,19 @@ void CGOpenMPRuntimeNVPTX::emitNonSPMDParallelCall(
// Force inline this outlined function at its call site.
Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
- Address ZeroAddr = CGF.CreateMemTemp(CGF.getContext().getIntTypeForBitwidth(
- /*DestWidth=*/32, /*Signed=*/1),
- ".zero.addr");
+ Address ZeroAddr = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty,
+ /*Name=*/".zero.addr");
CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0));
// ThreadId for serialized parallels is 0.
Address ThreadIDAddr = ZeroAddr;
- auto &&CodeGen = [this, Fn, CapturedVars, Loc, ZeroAddr, &ThreadIDAddr](
+ auto &&CodeGen = [this, Fn, CapturedVars, Loc, &ThreadIDAddr](
CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
+ Address ZeroAddr =
+ CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty,
+ /*Name=*/".bound.zero.addr");
+ CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0));
llvm::SmallVector<llvm::Value *, 16> OutlinedFnArgs;
OutlinedFnArgs.push_back(ThreadIDAddr.getPointer());
OutlinedFnArgs.push_back(ZeroAddr.getPointer());
@@ -2611,17 +2662,19 @@ void CGOpenMPRuntimeNVPTX::emitSPMDParallelCall(
//
llvm::SmallVector<llvm::Value *, 16> OutlinedFnArgs;
- Address ZeroAddr = CGF.CreateMemTemp(CGF.getContext().getIntTypeForBitwidth(
- /*DestWidth=*/32, /*Signed=*/1),
- ".zero.addr");
+ Address ZeroAddr = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty,
+ /*Name=*/".zero.addr");
CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0));
// ThreadId for serialized parallels is 0.
Address ThreadIDAddr = ZeroAddr;
- auto &&CodeGen = [this, OutlinedFn, CapturedVars, Loc, ZeroAddr,
- &ThreadIDAddr](CodeGenFunction &CGF,
- PrePostActionTy &Action) {
+ auto &&CodeGen = [this, OutlinedFn, CapturedVars, Loc, &ThreadIDAddr](
+ CodeGenFunction &CGF, PrePostActionTy &Action) {
Action.Enter(CGF);
+ Address ZeroAddr =
+ CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty,
+ /*Name=*/".bound.zero.addr");
+ CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0));
llvm::SmallVector<llvm::Value *, 16> OutlinedFnArgs;
OutlinedFnArgs.push_back(ThreadIDAddr.getPointer());
OutlinedFnArgs.push_back(ZeroAddr.getPointer());
@@ -2669,8 +2722,9 @@ void CGOpenMPRuntimeNVPTX::syncCTAThreads(CodeGenFunction &CGF) {
llvm::ConstantPointerNull::get(
cast<llvm::PointerType>(getIdentTyPointerTy())),
llvm::ConstantInt::get(CGF.Int32Ty, /*V=*/0, /*isSigned=*/true)};
- CGF.EmitRuntimeCall(
+ llvm::CallInst *Call = CGF.EmitRuntimeCall(
createNVPTXRuntimeFunction(OMPRTL__kmpc_barrier_simple_spmd), Args);
+ Call->setConvergent();
}
void CGOpenMPRuntimeNVPTX::emitBarrierCall(CodeGenFunction &CGF,
@@ -2684,7 +2738,9 @@ void CGOpenMPRuntimeNVPTX::emitBarrierCall(CodeGenFunction &CGF,
unsigned Flags = getDefaultFlagsForBarriers(Kind);
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, Flags),
getThreadID(CGF, Loc)};
- CGF.EmitRuntimeCall(createNVPTXRuntimeFunction(OMPRTL__kmpc_barrier), Args);
+ llvm::CallInst *Call = CGF.EmitRuntimeCall(
+ createNVPTXRuntimeFunction(OMPRTL__kmpc_barrier), Args);
+ Call->setConvergent();
}
void CGOpenMPRuntimeNVPTX::emitCriticalRegion(
@@ -2697,6 +2753,9 @@ void CGOpenMPRuntimeNVPTX::emitCriticalRegion(
llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.critical.body");
llvm::BasicBlock *ExitBB = CGF.createBasicBlock("omp.critical.exit");
+ // Get the mask of active threads in the warp.
+ llvm::Value *Mask = CGF.EmitRuntimeCall(
+ createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_warp_active_thread_mask));
// Fetch team-local id of the thread.
llvm::Value *ThreadID = getNVPTXThreadID(CGF);
@@ -2737,8 +2796,9 @@ void CGOpenMPRuntimeNVPTX::emitCriticalRegion(
// Block waits for all threads in current team to finish then increments the
// counter variable and returns to the loop.
CGF.EmitBlock(SyncBB);
- emitBarrierCall(CGF, Loc, OMPD_unknown, /*EmitChecks=*/false,
- /*ForceSimpleCall=*/true);
+ // Reconverge active threads in the warp.
+ (void)CGF.EmitRuntimeCall(
+ createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_syncwarp), Mask);
llvm::Value *IncCounterVal =
CGF.Builder.CreateNSWAdd(CounterVal, CGF.Builder.getInt32(1));
@@ -4239,7 +4299,7 @@ void CGOpenMPRuntimeNVPTX::emitReduction(
}
llvm::APInt ArraySize(/*unsigned int numBits=*/32, Size);
QualType ReductionArrayTy =
- C.getConstantArrayType(C.VoidPtrTy, ArraySize, ArrayType::Normal,
+ C.getConstantArrayType(C.VoidPtrTy, ArraySize, nullptr, ArrayType::Normal,
/*IndexTypeQuals=*/0);
Address ReductionList =
CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list");
@@ -4515,9 +4575,8 @@ llvm::Function *CGOpenMPRuntimeNVPTX::createParallelDataSharingWrapper(
const auto *RD = CS.getCapturedRecordDecl();
auto CurField = RD->field_begin();
- Address ZeroAddr = CGF.CreateMemTemp(
- CGF.getContext().getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1),
- /*Name*/ ".zero.addr");
+ Address ZeroAddr = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty,
+ /*Name=*/".zero.addr");
CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0));
// Get the array of arguments.
SmallVector<llvm::Value *, 8> Args;
@@ -4634,7 +4693,7 @@ void CGOpenMPRuntimeNVPTX::emitFunctionProlog(CodeGenFunction &CGF,
return;
auto I = FunctionGlobalizedDecls.try_emplace(CGF.CurFn).first;
I->getSecond().MappedParams =
- llvm::make_unique<CodeGenFunction::OMPMapVars>();
+ std::make_unique<CodeGenFunction::OMPMapVars>();
I->getSecond().GlobalRecord = GlobalizedVarsRecord;
I->getSecond().EscapedParameters.insert(
VarChecker.getEscapedParameters().begin(),
@@ -4700,7 +4759,7 @@ Address CGOpenMPRuntimeNVPTX::getAddressOfLocalVariable(CodeGenFunction &CGF,
/*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal,
CGM.getContext().getTargetAddressSpace(LangAS::cuda_constant));
CharUnits Align = CGM.getContext().getDeclAlign(VD);
- GV->setAlignment(Align.getQuantity());
+ GV->setAlignment(Align.getAsAlign());
return Address(GV, Align);
}
case OMPAllocateDeclAttr::OMPPTeamMemAlloc: {
@@ -4712,7 +4771,7 @@ Address CGOpenMPRuntimeNVPTX::getAddressOfLocalVariable(CodeGenFunction &CGF,
/*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal,
CGM.getContext().getTargetAddressSpace(LangAS::cuda_shared));
CharUnits Align = CGM.getContext().getDeclAlign(VD);
- GV->setAlignment(Align.getQuantity());
+ GV->setAlignment(Align.getAsAlign());
return Address(GV, Align);
}
case OMPAllocateDeclAttr::OMPLargeCapMemAlloc:
@@ -4723,7 +4782,7 @@ Address CGOpenMPRuntimeNVPTX::getAddressOfLocalVariable(CodeGenFunction &CGF,
llvm::GlobalValue::InternalLinkage,
llvm::Constant::getNullValue(VarTy), VD->getName());
CharUnits Align = CGM.getContext().getDeclAlign(VD);
- GV->setAlignment(Align.getQuantity());
+ GV->setAlignment(Align.getAsAlign());
return Address(GV, Align);
}
}
@@ -5026,7 +5085,7 @@ void CGOpenMPRuntimeNVPTX::clear() {
Size = llvm::alignTo(Size, RecAlignment);
llvm::APInt ArySize(/*numBits=*/64, Size);
QualType SubTy = C.getConstantArrayType(
- C.CharTy, ArySize, ArrayType::Normal, /*IndexTypeQuals=*/0);
+ C.CharTy, ArySize, nullptr, ArrayType::Normal, /*IndexTypeQuals=*/0);
const bool UseSharedMemory = Size <= SharedMemorySize;
auto *Field =
FieldDecl::Create(C, UseSharedMemory ? SharedStaticRD : StaticRD,
@@ -5053,7 +5112,7 @@ void CGOpenMPRuntimeNVPTX::clear() {
if (!SharedStaticRD->field_empty()) {
llvm::APInt ArySize(/*numBits=*/64, SharedMemorySize);
QualType SubTy = C.getConstantArrayType(
- C.CharTy, ArySize, ArrayType::Normal, /*IndexTypeQuals=*/0);
+ C.CharTy, ArySize, nullptr, ArrayType::Normal, /*IndexTypeQuals=*/0);
auto *Field = FieldDecl::Create(
C, SharedStaticRD, SourceLocation(), SourceLocation(), nullptr, SubTy,
C.getTrivialTypeSourceInfo(SubTy, SourceLocation()),
@@ -5086,11 +5145,12 @@ void CGOpenMPRuntimeNVPTX::clear() {
std::pair<unsigned, unsigned> SMsBlockPerSM = getSMsBlocksPerSM(CGM);
llvm::APInt Size1(32, SMsBlockPerSM.second);
QualType Arr1Ty =
- C.getConstantArrayType(StaticTy, Size1, ArrayType::Normal,
+ C.getConstantArrayType(StaticTy, Size1, nullptr, ArrayType::Normal,
/*IndexTypeQuals=*/0);
llvm::APInt Size2(32, SMsBlockPerSM.first);
- QualType Arr2Ty = C.getConstantArrayType(Arr1Ty, Size2, ArrayType::Normal,
- /*IndexTypeQuals=*/0);
+ QualType Arr2Ty =
+ C.getConstantArrayType(Arr1Ty, Size2, nullptr, ArrayType::Normal,
+ /*IndexTypeQuals=*/0);
llvm::Type *LLVMArr2Ty = CGM.getTypes().ConvertTypeForMem(Arr2Ty);
// FIXME: nvlink does not handle weak linkage correctly (object with the
// different size are reported as erroneous).
diff --git a/lib/CodeGen/CGOpenMPRuntimeNVPTX.h b/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
index e7fd458e7271..0f78627c95e6 100644
--- a/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
+++ b/lib/CodeGen/CGOpenMPRuntimeNVPTX.h
@@ -193,6 +193,18 @@ protected:
/// Full/Lightweight runtime mode. Used for better optimization.
unsigned getDefaultLocationReserved2Flags() const override;
+ /// Tries to emit declare variant function for \p OldGD from \p NewGD.
+ /// \param OrigAddr LLVM IR value for \p OldGD.
+ /// \param IsForDefinition true, if requested emission for the definition of
+ /// \p OldGD.
+ /// \returns true, was able to emit a definition function for \p OldGD, which
+ /// points to \p NewGD.
+ /// NVPTX backend does not support global aliases, so just use the function,
+ /// emitted for \p NewGD instead of \p OldGD.
+ bool tryEmitDeclareVariant(const GlobalDecl &NewGD, const GlobalDecl &OldGD,
+ llvm::GlobalValue *OrigAddr,
+ bool IsForDefinition) override;
+
public:
explicit CGOpenMPRuntimeNVPTX(CodeGenModule &CGM);
void clear() override;
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index dd0dea5b94a0..bb2629f89d3d 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -281,6 +281,17 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
case Stmt::OMPTaskLoopSimdDirectiveClass:
EmitOMPTaskLoopSimdDirective(cast<OMPTaskLoopSimdDirective>(*S));
break;
+ case Stmt::OMPMasterTaskLoopDirectiveClass:
+ EmitOMPMasterTaskLoopDirective(cast<OMPMasterTaskLoopDirective>(*S));
+ break;
+ case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
+ EmitOMPMasterTaskLoopSimdDirective(
+ cast<OMPMasterTaskLoopSimdDirective>(*S));
+ break;
+ case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
+ EmitOMPParallelMasterTaskLoopDirective(
+ cast<OMPParallelMasterTaskLoopDirective>(*S));
+ break;
case Stmt::OMPDistributeDirectiveClass:
EmitOMPDistributeDirective(cast<OMPDistributeDirective>(*S));
break;
@@ -1846,11 +1857,9 @@ llvm::Value* CodeGenFunction::EmitAsmInput(
InputExpr->EvaluateAsRValue(EVResult, getContext(), true);
llvm::APSInt IntResult;
- if (!EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(),
- getContext()))
- llvm_unreachable("Invalid immediate constant!");
-
- return llvm::ConstantInt::get(getLLVMContext(), IntResult);
+ if (EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(),
+ getContext()))
+ return llvm::ConstantInt::get(getLLVMContext(), IntResult);
}
Expr::EvalResult Result;
@@ -1986,6 +1995,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
std::vector<llvm::Type *> ResultTruncRegTypes;
std::vector<llvm::Type *> ArgTypes;
std::vector<llvm::Value*> Args;
+ llvm::BitVector ResultTypeRequiresCast;
// Keep track of inout constraints.
std::string InOutConstraints;
@@ -2024,13 +2034,23 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// If this is a register output, then make the inline asm return it
// by-value. If this is a memory result, return the value by-reference.
- if (!Info.allowsMemory() && hasScalarEvaluationKind(OutExpr->getType())) {
+ bool isScalarizableAggregate =
+ hasAggregateEvaluationKind(OutExpr->getType());
+ if (!Info.allowsMemory() && (hasScalarEvaluationKind(OutExpr->getType()) ||
+ isScalarizableAggregate)) {
Constraints += "=" + OutputConstraint;
ResultRegQualTys.push_back(OutExpr->getType());
ResultRegDests.push_back(Dest);
- ResultRegTypes.push_back(ConvertTypeForMem(OutExpr->getType()));
- ResultTruncRegTypes.push_back(ResultRegTypes.back());
-
+ ResultTruncRegTypes.push_back(ConvertTypeForMem(OutExpr->getType()));
+ if (Info.allowsRegister() && isScalarizableAggregate) {
+ ResultTypeRequiresCast.push_back(true);
+ unsigned Size = getContext().getTypeSize(OutExpr->getType());
+ llvm::Type *ConvTy = llvm::IntegerType::get(getLLVMContext(), Size);
+ ResultRegTypes.push_back(ConvTy);
+ } else {
+ ResultTypeRequiresCast.push_back(false);
+ ResultRegTypes.push_back(ResultTruncRegTypes.back());
+ }
// If this output is tied to an input, and if the input is larger, then
// we need to set the actual result type of the inline asm node to be the
// same as the input type.
@@ -2064,8 +2084,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Update largest vector width for any vector types.
if (auto *VT = dyn_cast<llvm::VectorType>(ResultRegTypes.back()))
- LargestVectorWidth = std::max(LargestVectorWidth,
- VT->getPrimitiveSizeInBits());
+ LargestVectorWidth = std::max((uint64_t)LargestVectorWidth,
+ VT->getPrimitiveSizeInBits().getFixedSize());
} else {
ArgTypes.push_back(Dest.getAddress().getType());
Args.push_back(Dest.getPointer());
@@ -2089,8 +2109,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Update largest vector width for any vector types.
if (auto *VT = dyn_cast<llvm::VectorType>(Arg->getType()))
- LargestVectorWidth = std::max(LargestVectorWidth,
- VT->getPrimitiveSizeInBits());
+ LargestVectorWidth = std::max((uint64_t)LargestVectorWidth,
+ VT->getPrimitiveSizeInBits().getFixedSize());
if (Info.allowsRegister())
InOutConstraints += llvm::utostr(i);
else
@@ -2176,8 +2196,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Update largest vector width for any vector types.
if (auto *VT = dyn_cast<llvm::VectorType>(Arg->getType()))
- LargestVectorWidth = std::max(LargestVectorWidth,
- VT->getPrimitiveSizeInBits());
+ LargestVectorWidth = std::max((uint64_t)LargestVectorWidth,
+ VT->getPrimitiveSizeInBits().getFixedSize());
ArgTypes.push_back(Arg->getType());
Args.push_back(Arg);
@@ -2273,6 +2293,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
assert(RegResults.size() == ResultRegTypes.size());
assert(RegResults.size() == ResultTruncRegTypes.size());
assert(RegResults.size() == ResultRegDests.size());
+ // ResultRegDests can be also populated by addReturnRegisterOutputs() above,
+ // in which case its size may grow.
+ assert(ResultTypeRequiresCast.size() <= ResultRegDests.size());
for (unsigned i = 0, e = RegResults.size(); i != e; ++i) {
llvm::Value *Tmp = RegResults[i];
@@ -2302,7 +2325,24 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
}
}
- EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i]);
+ LValue Dest = ResultRegDests[i];
+ // ResultTypeRequiresCast elements correspond to the first
+ // ResultTypeRequiresCast.size() elements of RegResults.
+ if ((i < ResultTypeRequiresCast.size()) && ResultTypeRequiresCast[i]) {
+ unsigned Size = getContext().getTypeSize(ResultRegQualTys[i]);
+ Address A = Builder.CreateBitCast(Dest.getAddress(),
+ ResultRegTypes[i]->getPointerTo());
+ QualType Ty = getContext().getIntTypeForBitwidth(Size, /*Signed*/ false);
+ if (Ty.isNull()) {
+ const Expr *OutExpr = S.getOutputExpr(i);
+ CGM.Error(
+ OutExpr->getExprLoc(),
+ "impossible constraint in asm: can't store value into a register");
+ return;
+ }
+ Dest = MakeAddrLValue(A, Ty);
+ }
+ EmitStoreThroughLValue(RValue::get(Tmp), Dest);
}
}
diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp
index e8fbca5108ad..6ece69d51daf 100644
--- a/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/lib/CodeGen/CGStmtOpenMP.cpp
@@ -120,12 +120,46 @@ public:
class OMPLoopScope : public CodeGenFunction::RunCleanupsScope {
void emitPreInitStmt(CodeGenFunction &CGF, const OMPLoopDirective &S) {
CodeGenFunction::OMPMapVars PreCondVars;
+ llvm::DenseSet<const VarDecl *> EmittedAsPrivate;
for (const auto *E : S.counters()) {
const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
+ EmittedAsPrivate.insert(VD->getCanonicalDecl());
(void)PreCondVars.setVarAddr(
CGF, VD, CGF.CreateMemTemp(VD->getType().getNonReferenceType()));
}
+ // Mark private vars as undefs.
+ for (const auto *C : S.getClausesOfKind<OMPPrivateClause>()) {
+ for (const Expr *IRef : C->varlists()) {
+ const auto *OrigVD = cast<VarDecl>(cast<DeclRefExpr>(IRef)->getDecl());
+ if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) {
+ (void)PreCondVars.setVarAddr(
+ CGF, OrigVD,
+ Address(llvm::UndefValue::get(
+ CGF.ConvertTypeForMem(CGF.getContext().getPointerType(
+ OrigVD->getType().getNonReferenceType()))),
+ CGF.getContext().getDeclAlign(OrigVD)));
+ }
+ }
+ }
(void)PreCondVars.apply(CGF);
+ // Emit init, __range and __end variables for C++ range loops.
+ const Stmt *Body =
+ S.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
+ for (unsigned Cnt = 0; Cnt < S.getCollapsedNumber(); ++Cnt) {
+ Body = Body->IgnoreContainers();
+ if (auto *For = dyn_cast<ForStmt>(Body)) {
+ Body = For->getBody();
+ } else {
+ assert(isa<CXXForRangeStmt>(Body) &&
+ "Expected canonical for loop or range-based for loop.");
+ auto *CXXFor = cast<CXXForRangeStmt>(Body);
+ if (const Stmt *Init = CXXFor->getInit())
+ CGF.EmitStmt(Init);
+ CGF.EmitStmt(CXXFor->getRangeStmt());
+ CGF.EmitStmt(CXXFor->getEndStmt());
+ Body = CXXFor->getBody();
+ }
+ }
if (const auto *PreInits = cast_or_null<DeclStmt>(S.getPreInits())) {
for (const auto *I : PreInits->decls())
CGF.EmitVarDecl(cast<VarDecl>(*I));
@@ -1324,6 +1358,31 @@ void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D,
// On a continue in the body, jump to the end.
JumpDest Continue = getJumpDestInCurrentScope("omp.body.continue");
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
+ for (const Expr *E : D.finals_conditions()) {
+ if (!E)
+ continue;
+ // Check that loop counter in non-rectangular nest fits into the iteration
+ // space.
+ llvm::BasicBlock *NextBB = createBasicBlock("omp.body.next");
+ EmitBranchOnBoolExpr(E, NextBB, Continue.getBlock(),
+ getProfileCount(D.getBody()));
+ EmitBlock(NextBB);
+ }
+ // Emit loop variables for C++ range loops.
+ const Stmt *Body =
+ D.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers();
+ for (unsigned Cnt = 0; Cnt < D.getCollapsedNumber(); ++Cnt) {
+ Body = Body->IgnoreContainers();
+ if (auto *For = dyn_cast<ForStmt>(Body)) {
+ Body = For->getBody();
+ } else {
+ assert(isa<CXXForRangeStmt>(Body) &&
+ "Expected canonical for loop or range-based for loop.");
+ auto *CXXFor = cast<CXXForRangeStmt>(Body);
+ EmitStmt(CXXFor->getLoopVarStmt());
+ Body = CXXFor->getBody();
+ }
+ }
// Emit loop body.
EmitStmt(D.getBody());
// The end (updates/cleanups).
@@ -1460,14 +1519,14 @@ static void emitAlignedClause(CodeGenFunction &CGF,
if (!CGF.HaveInsertPoint())
return;
for (const auto *Clause : D.getClausesOfKind<OMPAlignedClause>()) {
- unsigned ClauseAlignment = 0;
+ llvm::APInt ClauseAlignment(64, 0);
if (const Expr *AlignmentExpr = Clause->getAlignment()) {
auto *AlignmentCI =
cast<llvm::ConstantInt>(CGF.EmitScalarExpr(AlignmentExpr));
- ClauseAlignment = static_cast<unsigned>(AlignmentCI->getZExtValue());
+ ClauseAlignment = AlignmentCI->getValue();
}
for (const Expr *E : Clause->varlists()) {
- unsigned Alignment = ClauseAlignment;
+ llvm::APInt Alignment(ClauseAlignment);
if (Alignment == 0) {
// OpenMP [2.8.1, Description]
// If no optional parameter is specified, implementation-defined default
@@ -1478,12 +1537,13 @@ static void emitAlignedClause(CodeGenFunction &CGF,
E->getType()->getPointeeType()))
.getQuantity();
}
- assert((Alignment == 0 || llvm::isPowerOf2_32(Alignment)) &&
+ assert((Alignment == 0 || Alignment.isPowerOf2()) &&
"alignment is not power of 2");
if (Alignment != 0) {
llvm::Value *PtrValue = CGF.EmitScalarExpr(E);
CGF.EmitAlignmentAssumption(
- PtrValue, E, /*No second loc needed*/ SourceLocation(), Alignment);
+ PtrValue, E, /*No second loc needed*/ SourceLocation(),
+ llvm::ConstantInt::get(CGF.getLLVMContext(), Alignment));
}
}
}
@@ -1553,8 +1613,28 @@ static void emitPreCond(CodeGenFunction &CGF, const OMPLoopDirective &S,
CGF.EmitIgnoredExpr(I);
}
}
+ // Create temp loop control variables with their init values to support
+ // non-rectangular loops.
+ CodeGenFunction::OMPMapVars PreCondVars;
+ for (const Expr * E: S.dependent_counters()) {
+ if (!E)
+ continue;
+ assert(!E->getType().getNonReferenceType()->isRecordType() &&
+ "dependent counter must not be an iterator.");
+ const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl());
+ Address CounterAddr =
+ CGF.CreateMemTemp(VD->getType().getNonReferenceType());
+ (void)PreCondVars.setVarAddr(CGF, VD, CounterAddr);
+ }
+ (void)PreCondVars.apply(CGF);
+ for (const Expr *E : S.dependent_inits()) {
+ if (!E)
+ continue;
+ CGF.EmitIgnoredExpr(E);
+ }
// Check that loop is executed at least one time.
CGF.EmitBranchOnBoolExpr(Cond, TrueBlock, FalseBlock, TrueCount);
+ PreCondVars.restore(CGF);
}
void CodeGenFunction::EmitOMPLinearClause(
@@ -3044,7 +3124,8 @@ void CodeGenFunction::EmitOMPTaskBasedDirective(
llvm::Function *OutlinedFn = CGM.getOpenMPRuntime().emitTaskOutlinedFunction(
S, *I, *PartId, *TaskT, S.getDirectiveKind(), CodeGen, Data.Tied,
Data.NumberOfParts);
- OMPLexicalScope Scope(*this, S);
+ OMPLexicalScope Scope(*this, S, llvm::None,
+ !isOpenMPParallelDirective(S.getDirectiveKind()));
TaskGen(*this, OutlinedFn, Data);
}
@@ -3112,7 +3193,7 @@ void CodeGenFunction::EmitOMPTargetTaskBasedDirective(
getContext(), getContext().getTranslationUnitDecl(), /*NumParams=*/0);
llvm::APInt ArrSize(/*numBits=*/32, InputInfo.NumberOfTargetItems);
QualType BaseAndPointersType = getContext().getConstantArrayType(
- getContext().VoidPtrTy, ArrSize, ArrayType::Normal,
+ getContext().VoidPtrTy, ArrSize, nullptr, ArrayType::Normal,
/*IndexTypeQuals=*/0);
BPVD = createImplicitFirstprivateForType(
getContext(), Data, BaseAndPointersType, CD, S.getBeginLoc());
@@ -3120,7 +3201,7 @@ void CodeGenFunction::EmitOMPTargetTaskBasedDirective(
getContext(), Data, BaseAndPointersType, CD, S.getBeginLoc());
QualType SizesType = getContext().getConstantArrayType(
getContext().getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1),
- ArrSize, ArrayType::Normal,
+ ArrSize, nullptr, ArrayType::Normal,
/*IndexTypeQuals=*/0);
SVD = createImplicitFirstprivateForType(getContext(), Data, SizesType, CD,
S.getBeginLoc());
@@ -3991,6 +4072,8 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed in 'omp atomic'.");
}
}
@@ -4090,18 +4173,21 @@ static void emitCommonOMPTargetDirective(CodeGenFunction &CGF,
CGM.getOpenMPRuntime().emitTargetOutlinedFunction(S, ParentName, Fn, FnID,
IsOffloadEntry, CodeGen);
OMPLexicalScope Scope(CGF, S, OMPD_task);
- auto &&SizeEmitter = [](CodeGenFunction &CGF, const OMPLoopDirective &D) {
- OMPLoopScope(CGF, D);
- // Emit calculation of the iterations count.
- llvm::Value *NumIterations = CGF.EmitScalarExpr(D.getNumIterations());
- NumIterations = CGF.Builder.CreateIntCast(NumIterations, CGF.Int64Ty,
- /*isSigned=*/false);
- return NumIterations;
+ auto &&SizeEmitter =
+ [IsOffloadEntry](CodeGenFunction &CGF,
+ const OMPLoopDirective &D) -> llvm::Value * {
+ if (IsOffloadEntry) {
+ OMPLoopScope(CGF, D);
+ // Emit calculation of the iterations count.
+ llvm::Value *NumIterations = CGF.EmitScalarExpr(D.getNumIterations());
+ NumIterations = CGF.Builder.CreateIntCast(NumIterations, CGF.Int64Ty,
+ /*isSigned=*/false);
+ return NumIterations;
+ }
+ return nullptr;
};
- if (IsOffloadEntry)
- CGM.getOpenMPRuntime().emitTargetNumIterationsCall(CGF, S, Device,
- SizeEmitter);
- CGM.getOpenMPRuntime().emitTargetCall(CGF, S, Fn, FnID, IfCond, Device);
+ CGM.getOpenMPRuntime().emitTargetCall(CGF, S, Fn, FnID, IfCond, Device,
+ SizeEmitter);
}
static void emitTargetRegion(CodeGenFunction &CGF, const OMPTargetDirective &S,
@@ -5025,6 +5111,42 @@ void CodeGenFunction::EmitOMPTaskLoopSimdDirective(
EmitOMPTaskLoopBasedDirective(S);
}
+void CodeGenFunction::EmitOMPMasterTaskLoopDirective(
+ const OMPMasterTaskLoopDirective &S) {
+ auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
+ Action.Enter(CGF);
+ EmitOMPTaskLoopBasedDirective(S);
+ };
+ OMPLexicalScope Scope(*this, S, llvm::None, /*EmitPreInitStmt=*/false);
+ CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getBeginLoc());
+}
+
+void CodeGenFunction::EmitOMPMasterTaskLoopSimdDirective(
+ const OMPMasterTaskLoopSimdDirective &S) {
+ auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
+ Action.Enter(CGF);
+ EmitOMPTaskLoopBasedDirective(S);
+ };
+ OMPLexicalScope Scope(*this, S, llvm::None, /*EmitPreInitStmt=*/false);
+ CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getBeginLoc());
+}
+
+void CodeGenFunction::EmitOMPParallelMasterTaskLoopDirective(
+ const OMPParallelMasterTaskLoopDirective &S) {
+ auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
+ auto &&TaskLoopCodeGen = [&S](CodeGenFunction &CGF,
+ PrePostActionTy &Action) {
+ Action.Enter(CGF);
+ CGF.EmitOMPTaskLoopBasedDirective(S);
+ };
+ OMPLexicalScope Scope(CGF, S, llvm::None, /*EmitPreInitStmt=*/false);
+ CGM.getOpenMPRuntime().emitMasterRegion(CGF, TaskLoopCodeGen,
+ S.getBeginLoc());
+ };
+ emitCommonOMPParallelDirective(*this, S, OMPD_master_taskloop, CodeGen,
+ emitEmptyBoundParameters);
+}
+
// Generate the instructions for '#pragma omp target update' directive.
void CodeGenFunction::EmitOMPTargetUpdateDirective(
const OMPTargetUpdateDirective &S) {
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 3cb3d3544838..f9f25e7e57ad 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -157,7 +157,7 @@ CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn,
const CGFunctionInfo &FnInfo,
GlobalDecl GD, const ThunkInfo &Thunk) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
QualType ResultType = FPT->getReturnType();
// Get the original function
@@ -166,6 +166,15 @@ CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn,
llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true);
llvm::Function *BaseFn = cast<llvm::Function>(Callee);
+ // Cloning can't work if we don't have a definition. The Microsoft ABI may
+ // require thunks when a definition is not available. Emit an error in these
+ // cases.
+ if (!MD->isDefined()) {
+ CGM.ErrorUnsupported(MD, "return-adjusting thunk with variadic arguments");
+ return Fn;
+ }
+ assert(!BaseFn->isDeclaration() && "cannot clone undefined variadic method");
+
// Clone to thunk.
llvm::ValueToValueMapTy VMap;
@@ -201,6 +210,8 @@ CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn,
Builder.SetInsertPoint(&*ThisStore);
llvm::Value *AdjustedThisPtr =
CGM.getCXXABI().performThisAdjustment(*this, ThisPtr, Thunk.This);
+ AdjustedThisPtr = Builder.CreateBitCast(AdjustedThisPtr,
+ ThisStore->getOperand(0)->getType());
ThisStore->setOperand(0, AdjustedThisPtr);
if (!Thunk.Return.isEmpty()) {
@@ -231,7 +242,6 @@ void CodeGenFunction::StartThunk(llvm::Function *Fn, GlobalDecl GD,
// Build FunctionArgs.
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
QualType ThisType = MD->getThisType();
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
QualType ResultType;
if (IsUnprototyped)
ResultType = CGM.getContext().VoidTy;
@@ -240,7 +250,7 @@ void CodeGenFunction::StartThunk(llvm::Function *Fn, GlobalDecl GD,
else if (CGM.getCXXABI().hasMostDerivedReturn(GD))
ResultType = CGM.getContext().VoidPtrTy;
else
- ResultType = FPT->getReturnType();
+ ResultType = MD->getType()->castAs<FunctionProtoType>()->getReturnType();
FunctionArgList FunctionArgs;
// Create the implicit 'this' parameter declaration.
@@ -291,14 +301,17 @@ void CodeGenFunction::EmitCallAndReturnForThunk(llvm::FunctionCallee Callee,
*this, LoadCXXThisAddress(), Thunk->This)
: LoadCXXThis();
- if (CurFnInfo->usesInAlloca() || IsUnprototyped) {
- // We don't handle return adjusting thunks, because they require us to call
- // the copy constructor. For now, fall through and pretend the return
- // adjustment was empty so we don't crash.
+ // If perfect forwarding is required a variadic method, a method using
+ // inalloca, or an unprototyped thunk, use musttail. Emit an error if this
+ // thunk requires a return adjustment, since that is impossible with musttail.
+ if (CurFnInfo->usesInAlloca() || CurFnInfo->isVariadic() || IsUnprototyped) {
if (Thunk && !Thunk->Return.isEmpty()) {
if (IsUnprototyped)
CGM.ErrorUnsupported(
MD, "return-adjusting thunk with incomplete parameter type");
+ else if (CurFnInfo->isVariadic())
+ llvm_unreachable("shouldn't try to emit musttail return-adjusting "
+ "thunks for variadic functions");
else
CGM.ErrorUnsupported(
MD, "non-trivial argument copy for return-adjusting thunk");
@@ -549,16 +562,32 @@ llvm::Constant *CodeGenVTables::maybeEmitThunk(GlobalDecl GD,
CGM.SetLLVMFunctionAttributesForDefinition(GD.getDecl(), ThunkFn);
+ // Thunks for variadic methods are special because in general variadic
+ // arguments cannot be perferctly forwarded. In the general case, clang
+ // implements such thunks by cloning the original function body. However, for
+ // thunks with no return adjustment on targets that support musttail, we can
+ // use musttail to perfectly forward the variadic arguments.
+ bool ShouldCloneVarArgs = false;
if (!IsUnprototyped && ThunkFn->isVarArg()) {
- // Varargs thunks are special; we can't just generate a call because
- // we can't copy the varargs. Our implementation is rather
- // expensive/sucky at the moment, so don't generate the thunk unless
- // we have to.
- // FIXME: Do something better here; GenerateVarArgsThunk is extremely ugly.
+ ShouldCloneVarArgs = true;
+ if (TI.Return.isEmpty()) {
+ switch (CGM.getTriple().getArch()) {
+ case llvm::Triple::x86_64:
+ case llvm::Triple::x86:
+ case llvm::Triple::aarch64:
+ ShouldCloneVarArgs = false;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (ShouldCloneVarArgs) {
if (UseAvailableExternallyLinkage)
return ThunkFn;
- ThunkFn = CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD,
- TI);
+ ThunkFn =
+ CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, TI);
} else {
// Normal thunk body generation.
CodeGenFunction(CGM).generateThunk(ThunkFn, FnInfo, GD, TI, IsUnprototyped);
@@ -779,7 +808,7 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
assert(!VTable->isDeclaration() && "Shouldn't set properties on declaration");
CGM.setGVProperties(VTable, RD);
- CGM.EmitVTableTypeMetadata(VTable, *VTLayout.get());
+ CGM.EmitVTableTypeMetadata(RD, VTable, *VTLayout.get());
return VTable;
}
@@ -1010,7 +1039,32 @@ bool CodeGenModule::HasHiddenLTOVisibility(const CXXRecordDecl *RD) {
return true;
}
-void CodeGenModule::EmitVTableTypeMetadata(llvm::GlobalVariable *VTable,
+llvm::GlobalObject::VCallVisibility
+CodeGenModule::GetVCallVisibilityLevel(const CXXRecordDecl *RD) {
+ LinkageInfo LV = RD->getLinkageAndVisibility();
+ llvm::GlobalObject::VCallVisibility TypeVis;
+ if (!isExternallyVisible(LV.getLinkage()))
+ TypeVis = llvm::GlobalObject::VCallVisibilityTranslationUnit;
+ else if (HasHiddenLTOVisibility(RD))
+ TypeVis = llvm::GlobalObject::VCallVisibilityLinkageUnit;
+ else
+ TypeVis = llvm::GlobalObject::VCallVisibilityPublic;
+
+ for (auto B : RD->bases())
+ if (B.getType()->getAsCXXRecordDecl()->isDynamicClass())
+ TypeVis = std::min(TypeVis,
+ GetVCallVisibilityLevel(B.getType()->getAsCXXRecordDecl()));
+
+ for (auto B : RD->vbases())
+ if (B.getType()->getAsCXXRecordDecl()->isDynamicClass())
+ TypeVis = std::min(TypeVis,
+ GetVCallVisibilityLevel(B.getType()->getAsCXXRecordDecl()));
+
+ return TypeVis;
+}
+
+void CodeGenModule::EmitVTableTypeMetadata(const CXXRecordDecl *RD,
+ llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout) {
if (!getCodeGenOpts().LTOUnit)
return;
@@ -1070,4 +1124,10 @@ void CodeGenModule::EmitVTableTypeMetadata(llvm::GlobalVariable *VTable,
VTable->addTypeMetadata((PointerWidth * I).getQuantity(), MD);
}
}
+
+ if (getCodeGenOpts().VirtualFunctionElimination) {
+ llvm::GlobalObject::VCallVisibility TypeVis = GetVCallVisibilityLevel(RD);
+ if (TypeVis != llvm::GlobalObject::VCallVisibilityPublic)
+ VTable->addVCallVisibilityMetadata(TypeVis);
+ }
}
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index 0ae9ea427d65..87bda4a0fc2c 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -14,7 +14,9 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
+#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangStandard.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/BackendUtil.h"
@@ -37,6 +39,7 @@
#include "llvm/Pass.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/YAMLTraits.h"
@@ -228,6 +231,7 @@ namespace clang {
void HandleTranslationUnit(ASTContext &C) override {
{
+ llvm::TimeTraceScope TimeScope("Frontend", StringRef(""));
PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
if (FrontendTimesIsEnabled) {
LLVMIRGenerationRefCount += 1;
@@ -260,7 +264,7 @@ namespace clang {
std::unique_ptr<DiagnosticHandler> OldDiagnosticHandler =
Ctx.getDiagnosticHandler();
- Ctx.setDiagnosticHandler(llvm::make_unique<ClangDiagnosticHandler>(
+ Ctx.setDiagnosticHandler(std::make_unique<ClangDiagnosticHandler>(
CodeGenOpts, this));
Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr =
@@ -362,6 +366,9 @@ namespace clang {
bool StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D);
/// Specialized handler for unsupported backend feature diagnostic.
void UnsupportedDiagHandler(const llvm::DiagnosticInfoUnsupported &D);
+ /// Specialized handler for misexpect warnings.
+ /// Note that misexpect remarks are emitted through ORE
+ void MisExpectDiagHandler(const llvm::DiagnosticInfoMisExpect &D);
/// Specialized handlers for optimization remarks.
/// Note that these handlers only accept remarks and they always handle
/// them.
@@ -561,13 +568,13 @@ const FullSourceLoc BackendConsumer::getBestLocationFromDebugLoc(
if (D.isLocationAvailable()) {
D.getLocation(Filename, Line, Column);
if (Line > 0) {
- const FileEntry *FE = FileMgr.getFile(Filename);
+ auto FE = FileMgr.getFile(Filename);
if (!FE)
FE = FileMgr.getFile(D.getAbsolutePath());
if (FE) {
// If -gcolumn-info was not used, Column will be 0. This upsets the
// source manager, so pass 1 if Column is not set.
- DILoc = SourceMgr.translateFileLineCol(FE, Line, Column ? Column : 1);
+ DILoc = SourceMgr.translateFileLineCol(*FE, Line, Column ? Column : 1);
}
}
BadDebugInfo = DILoc.isInvalid();
@@ -614,6 +621,25 @@ void BackendConsumer::UnsupportedDiagHandler(
<< Filename << Line << Column;
}
+void BackendConsumer::MisExpectDiagHandler(
+ const llvm::DiagnosticInfoMisExpect &D) {
+ StringRef Filename;
+ unsigned Line, Column;
+ bool BadDebugInfo = false;
+ FullSourceLoc Loc =
+ getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column);
+
+ Diags.Report(Loc, diag::warn_profile_data_misexpect) << D.getMsg().str();
+
+ if (BadDebugInfo)
+ // If we were not able to translate the file:line:col information
+ // back to a SourceLocation, at least emit a note stating that
+ // we could not translate this location. This can happen in the
+ // case of #line directives.
+ Diags.Report(Loc, diag::note_fe_backend_invalid_loc)
+ << Filename << Line << Column;
+}
+
void BackendConsumer::EmitOptimizationMessage(
const llvm::DiagnosticInfoOptimizationBase &D, unsigned DiagID) {
// We only support warnings and remarks.
@@ -784,6 +810,9 @@ void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) {
case llvm::DK_Unsupported:
UnsupportedDiagHandler(cast<DiagnosticInfoUnsupported>(DI));
return;
+ case llvm::DK_MisExpect:
+ MisExpectDiagHandler(cast<DiagnosticInfoMisExpect>(DI));
+ return;
default:
// Plugin IDs are not bound to any value as they are set dynamically.
ComputeDiagRemarkID(Severity, backend_plugin, DiagID);
@@ -914,7 +943,7 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
if (CI.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo &&
CI.getCodeGenOpts().MacroDebugInfo) {
std::unique_ptr<PPCallbacks> Callbacks =
- llvm::make_unique<MacroPPCallbacks>(BEConsumer->getCodeGenerator(),
+ std::make_unique<MacroPPCallbacks>(BEConsumer->getCodeGenerator(),
CI.getPreprocessor());
CI.getPreprocessor().addPPCallbacks(std::move(Callbacks));
}
@@ -975,7 +1004,7 @@ CodeGenAction::loadModule(MemoryBufferRef MBRef) {
// the file was already processed by indexing and will be passed to the
// linker using merged object file.
if (!Bm) {
- auto M = llvm::make_unique<llvm::Module>("empty", *VMContext);
+ auto M = std::make_unique<llvm::Module>("empty", *VMContext);
M->setTargetTriple(CI.getTargetOpts().Triple);
return M;
}
@@ -1014,7 +1043,7 @@ CodeGenAction::loadModule(MemoryBufferRef MBRef) {
void CodeGenAction::ExecuteAction() {
// If this is an IR file, we have to treat it specially.
- if (getCurrentFileKind().getLanguage() == InputKind::LLVM_IR) {
+ if (getCurrentFileKind().getLanguage() == Language::LLVM_IR) {
BackendAction BA = static_cast<BackendAction>(Act);
CompilerInstance &CI = getCompilerInstance();
std::unique_ptr<raw_pwrite_stream> OS =
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index eafe26674434..3f9a52ab7638 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -47,13 +47,10 @@ static bool shouldEmitLifetimeMarkers(const CodeGenOptions &CGOpts,
if (CGOpts.DisableLifetimeMarkers)
return false;
- // Disable lifetime markers in msan builds.
- // FIXME: Remove this when msan works with lifetime markers.
- if (LangOpts.Sanitize.has(SanitizerKind::Memory))
- return false;
-
- // Asan uses markers for use-after-scope checks.
- if (CGOpts.SanitizeAddressUseAfterScope)
+ // Sanitizers may use markers.
+ if (CGOpts.SanitizeAddressUseAfterScope ||
+ LangOpts.Sanitize.has(SanitizerKind::HWAddress) ||
+ LangOpts.Sanitize.has(SanitizerKind::Memory))
return true;
// For now, only in optimized builds.
@@ -197,7 +194,7 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
#define NON_CANONICAL_TYPE(name, parent) case Type::name:
#define DEPENDENT_TYPE(name, parent) case Type::name:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(name, parent) case Type::name:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("non-canonical or dependent type in IR-generation");
case Type::Auto:
@@ -434,13 +431,13 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
// Scan function arguments for vector width.
for (llvm::Argument &A : CurFn->args())
if (auto *VT = dyn_cast<llvm::VectorType>(A.getType()))
- LargestVectorWidth = std::max(LargestVectorWidth,
- VT->getPrimitiveSizeInBits());
+ LargestVectorWidth = std::max((uint64_t)LargestVectorWidth,
+ VT->getPrimitiveSizeInBits().getFixedSize());
// Update vector width based on return type.
if (auto *VT = dyn_cast<llvm::VectorType>(CurFn->getReturnType()))
- LargestVectorWidth = std::max(LargestVectorWidth,
- VT->getPrimitiveSizeInBits());
+ LargestVectorWidth = std::max((uint64_t)LargestVectorWidth,
+ VT->getPrimitiveSizeInBits().getFixedSize());
// Add the required-vector-width attribute. This contains the max width from:
// 1. min-vector-width attribute used in the source program.
@@ -732,6 +729,15 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
SanOpts.Mask &= ~SanitizerKind::CFIUnrelatedCast;
}
+ // Ignore null checks in coroutine functions since the coroutines passes
+ // are not aware of how to move the extra UBSan instructions across the split
+ // coroutine boundaries.
+ if (D && SanOpts.has(SanitizerKind::Null))
+ if (const auto *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->getBody() &&
+ FD->getBody()->getStmtClass() == Stmt::CoroutineBodyStmtClass)
+ SanOpts.Mask &= ~SanitizerKind::Null;
+
// Apply xray attributes to the function (as a string, for now)
if (D) {
if (const auto *XRayAttr = D->getAttr<XRayInstrumentAttr>()) {
@@ -762,6 +768,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
if (CGM.getCodeGenOpts().ProfileSampleAccurate)
Fn->addFnAttr("profile-sample-accurate");
+ if (D && D->hasAttr<CFICanonicalJumpTableAttr>())
+ Fn->addFnAttr("cfi-canonical-jump-table");
+
if (getLangOpts().OpenCL) {
// Add metadata for a kernel function.
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
@@ -1662,7 +1671,7 @@ CodeGenFunction::EmitNullInitialization(Address DestPtr, QualType Ty) {
llvm::GlobalVariable::PrivateLinkage,
NullConstant, Twine());
CharUnits NullAlign = DestPtr.getAlignment();
- NullVariable->setAlignment(NullAlign.getQuantity());
+ NullVariable->setAlignment(NullAlign.getAsAlign());
Address SrcPtr(Builder.CreateBitCast(NullVariable, Builder.getInt8PtrTy()),
NullAlign);
@@ -1862,7 +1871,7 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
#define NON_CANONICAL_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("unexpected dependent type!");
// These types are never variably-modified.
@@ -2048,24 +2057,9 @@ void CodeGenFunction::EmitAlignmentAssumption(llvm::Value *PtrValue,
}
void CodeGenFunction::EmitAlignmentAssumption(llvm::Value *PtrValue,
- QualType Ty, SourceLocation Loc,
- SourceLocation AssumptionLoc,
- unsigned Alignment,
- llvm::Value *OffsetValue) {
- llvm::Value *TheCheck;
- llvm::Instruction *Assumption = Builder.CreateAlignmentAssumption(
- CGM.getDataLayout(), PtrValue, Alignment, OffsetValue, &TheCheck);
- if (SanOpts.has(SanitizerKind::Alignment)) {
- llvm::Value *AlignmentVal = llvm::ConstantInt::get(IntPtrTy, Alignment);
- EmitAlignmentAssumptionCheck(PtrValue, Ty, Loc, AssumptionLoc, AlignmentVal,
- OffsetValue, TheCheck, Assumption);
- }
-}
-
-void CodeGenFunction::EmitAlignmentAssumption(llvm::Value *PtrValue,
const Expr *E,
SourceLocation AssumptionLoc,
- unsigned Alignment,
+ llvm::Value *Alignment,
llvm::Value *OffsetValue) {
if (auto *CE = dyn_cast<CastExpr>(E))
E = CE->getSubExprAsWritten();
@@ -2194,7 +2188,7 @@ void CodeGenFunction::checkTargetFeatures(SourceLocation Loc,
// Get the current enclosing function if it exists. If it doesn't
// we can't check the target features anyhow.
- const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl);
+ const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurCodeDecl);
if (!FD)
return;
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index c3060d1fb351..99bc85ba3773 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1034,7 +1034,7 @@ public:
assert(isInConditionalBranch());
llvm::BasicBlock *block = OutermostConditional->getStartingBlock();
auto store = new llvm::StoreInst(value, addr.getPointer(), &block->back());
- store->setAlignment(addr.getAlignment().getQuantity());
+ store->setAlignment(addr.getAlignment().getAsAlign());
}
/// An RAII object to record that we're evaluating a statement
@@ -2829,13 +2829,8 @@ public:
llvm::Value *Alignment,
llvm::Value *OffsetValue = nullptr);
- void EmitAlignmentAssumption(llvm::Value *PtrValue, QualType Ty,
- SourceLocation Loc, SourceLocation AssumptionLoc,
- unsigned Alignment,
- llvm::Value *OffsetValue = nullptr);
-
void EmitAlignmentAssumption(llvm::Value *PtrValue, const Expr *E,
- SourceLocation AssumptionLoc, unsigned Alignment,
+ SourceLocation AssumptionLoc, llvm::Value *Alignment,
llvm::Value *OffsetValue = nullptr);
//===--------------------------------------------------------------------===//
@@ -3160,6 +3155,11 @@ public:
void EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S);
void EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S);
void EmitOMPTaskLoopSimdDirective(const OMPTaskLoopSimdDirective &S);
+ void EmitOMPMasterTaskLoopDirective(const OMPMasterTaskLoopDirective &S);
+ void
+ EmitOMPMasterTaskLoopSimdDirective(const OMPMasterTaskLoopSimdDirective &S);
+ void EmitOMPParallelMasterTaskLoopDirective(
+ const OMPParallelMasterTaskLoopDirective &S);
void EmitOMPDistributeDirective(const OMPDistributeDirective &S);
void EmitOMPDistributeParallelForDirective(
const OMPDistributeParallelForDirective &S);
@@ -3760,6 +3760,7 @@ public:
llvm::Value *vectorWrapScalar16(llvm::Value *Op);
llvm::Value *EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E,
llvm::Triple::ArchType Arch);
+ llvm::Value *EmitBPFBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *BuildVector(ArrayRef<llvm::Value*> Ops);
llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 6ff72ec045e6..b05a58848e82 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -414,12 +414,7 @@ void CodeGenModule::Release() {
OpenMPRuntime->emitRequiresDirectiveRegFun()) {
AddGlobalCtor(OpenMPRequiresDirectiveRegFun, 0);
}
- if (llvm::Function *OpenMPRegistrationFunction =
- OpenMPRuntime->emitRegistrationFunction()) {
- auto ComdatKey = OpenMPRegistrationFunction->hasComdat() ?
- OpenMPRegistrationFunction : nullptr;
- AddGlobalCtor(OpenMPRegistrationFunction, 0, ComdatKey);
- }
+ OpenMPRuntime->createOffloadEntriesAndInfoMetadata();
OpenMPRuntime->clear();
}
if (PGOReader) {
@@ -535,6 +530,12 @@ void CodeGenModule::Release() {
getModule().addModuleFlag(llvm::Module::Override, "Cross-DSO CFI", 1);
}
+ if (LangOpts.Sanitize.has(SanitizerKind::CFIICall)) {
+ getModule().addModuleFlag(llvm::Module::Override,
+ "CFI Canonical Jump Tables",
+ CodeGenOpts.SanitizeCfiCanonicalJumpTables);
+ }
+
if (CodeGenOpts.CFProtectionReturn &&
Target.checkCFProtectionReturnSupported(getDiags())) {
// Indicate that we want to instrument return control flow protection.
@@ -1176,7 +1177,7 @@ void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) {
// The LTO linker doesn't seem to like it when we set an alignment
// on appending variables. Take it off as a workaround.
- list->setAlignment(0);
+ list->setAlignment(llvm::None);
Fns.clear();
}
@@ -1590,11 +1591,11 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();
if (alignment)
- F->setAlignment(alignment);
+ F->setAlignment(llvm::Align(alignment));
if (!D->hasAttr<AlignedAttr>())
if (LangOpts.FunctionAlignment)
- F->setAlignment(1 << LangOpts.FunctionAlignment);
+ F->setAlignment(llvm::Align(1ull << LangOpts.FunctionAlignment));
// Some C++ ABIs require 2-byte alignment for member functions, in order to
// reserve a bit for differentiating between virtual and non-virtual member
@@ -1602,13 +1603,20 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
// member function, set its alignment accordingly.
if (getTarget().getCXXABI().areMemberFunctionsAligned()) {
if (F->getAlignment() < 2 && isa<CXXMethodDecl>(D))
- F->setAlignment(2);
+ F->setAlignment(llvm::Align(2));
}
- // In the cross-dso CFI mode, we want !type attributes on definitions only.
- if (CodeGenOpts.SanitizeCfiCrossDso)
- if (auto *FD = dyn_cast<FunctionDecl>(D))
- CreateFunctionTypeMetadataForIcall(FD, F);
+ // In the cross-dso CFI mode with canonical jump tables, we want !type
+ // attributes on definitions only.
+ if (CodeGenOpts.SanitizeCfiCrossDso &&
+ CodeGenOpts.SanitizeCfiCanonicalJumpTables) {
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ // Skip available_externally functions. They won't be codegen'ed in the
+ // current module anyway.
+ if (getContext().GetGVALinkageForFunction(FD) != GVA_AvailableExternally)
+ CreateFunctionTypeMetadataForIcall(FD, F);
+ }
+ }
// Emit type metadata on member functions for member function pointer checks.
// These are only ever necessary on definitions; we're guaranteed that the
@@ -1704,6 +1712,8 @@ void CodeGenModule::setNonAliasAttributes(GlobalDecl GD,
GV->addAttribute("data-section", SA->getName());
if (auto *SA = D->getAttr<PragmaClangRodataSectionAttr>())
GV->addAttribute("rodata-section", SA->getName());
+ if (auto *SA = D->getAttr<PragmaClangRelroSectionAttr>())
+ GV->addAttribute("relro-section", SA->getName());
}
if (auto *F = dyn_cast<llvm::Function>(GO)) {
@@ -1765,14 +1775,6 @@ void CodeGenModule::CreateFunctionTypeMetadataForIcall(const FunctionDecl *FD,
if (isa<CXXMethodDecl>(FD) && !cast<CXXMethodDecl>(FD)->isStatic())
return;
- // Additionally, if building with cross-DSO support...
- if (CodeGenOpts.SanitizeCfiCrossDso) {
- // Skip available_externally functions. They won't be codegen'ed in the
- // current module anyway.
- if (getContext().GetGVALinkageForFunction(FD) == GVA_AvailableExternally)
- return;
- }
-
llvm::Metadata *MD = CreateMetadataIdentifierForType(FD->getType());
F->addTypeMetadata(0, MD);
F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
@@ -1849,8 +1851,11 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F,
F->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
// Don't emit entries for function declarations in the cross-DSO mode. This
- // is handled with better precision by the receiving DSO.
- if (!CodeGenOpts.SanitizeCfiCrossDso)
+ // is handled with better precision by the receiving DSO. But if jump tables
+ // are non-canonical then we need type metadata in order to produce the local
+ // jump table.
+ if (!CodeGenOpts.SanitizeCfiCrossDso ||
+ !CodeGenOpts.SanitizeCfiCanonicalJumpTables)
CreateFunctionTypeMetadataForIcall(FD, F);
if (getLangOpts().OpenMP && FD->hasAttr<OMPDeclareSimdDeclAttr>())
@@ -2114,6 +2119,10 @@ void CodeGenModule::EmitDeferred() {
if (!GV->isDeclaration())
continue;
+ // If this is OpenMP, check if it is legal to emit this global normally.
+ if (LangOpts.OpenMP && OpenMPRuntime && OpenMPRuntime->emitTargetGlobal(D))
+ continue;
+
// Otherwise, emit the definition and move on to the next one.
EmitGlobalDefinition(D, GV);
@@ -2310,11 +2319,20 @@ bool CodeGenModule::MustBeEmitted(const ValueDecl *Global) {
}
bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) {
- if (const auto *FD = dyn_cast<FunctionDecl>(Global))
+ if (const auto *FD = dyn_cast<FunctionDecl>(Global)) {
if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
// Implicit template instantiations may change linkage if they are later
// explicitly instantiated, so they should not be emitted eagerly.
return false;
+ // In OpenMP 5.0 function may be marked as device_type(nohost) and we should
+ // not emit them eagerly unless we sure that the function must be emitted on
+ // the host.
+ if (LangOpts.OpenMP >= 50 && !LangOpts.OpenMPSimd &&
+ !LangOpts.OpenMPIsDevice &&
+ !OMPDeclareTargetDeclAttr::getDeviceType(FD) &&
+ !FD->isUsed(/*CheckUsedAttr=*/false) && !FD->isReferenced())
+ return false;
+ }
if (const auto *VD = dyn_cast<VarDecl>(Global))
if (Context.getInlineVariableDefinitionKind(VD) ==
ASTContext::InlineVariableDefinitionKind::WeakUnknown)
@@ -2437,8 +2455,7 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
}
if (LangOpts.OpenMP) {
- // If this is OpenMP device, check if it is legal to emit this global
- // normally.
+ // If this is OpenMP, check if it is legal to emit this global normally.
if (OpenMPRuntime && OpenMPRuntime->emitTargetGlobal(GD))
return;
if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(Global)) {
@@ -2512,6 +2529,11 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
return;
}
+ // Check if this must be emitted as declare variant.
+ if (LangOpts.OpenMP && isa<FunctionDecl>(Global) && OpenMPRuntime &&
+ OpenMPRuntime->emitDeclareVariant(GD, /*IsForDefinition=*/false))
+ return;
+
// If we're deferring emission of a C++ variable with an
// initializer, remember the order in which it appeared in the file.
if (getLangOpts().CPlusPlus && isa<VarDecl>(Global) &&
@@ -2717,6 +2739,50 @@ void CodeGenModule::EmitMultiVersionFunctionDefinition(GlobalDecl GD,
EmitGlobalFunctionDefinition(GD, GV);
}
+void CodeGenModule::emitOpenMPDeviceFunctionRedefinition(
+ GlobalDecl OldGD, GlobalDecl NewGD, llvm::GlobalValue *GV) {
+ assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice &&
+ OpenMPRuntime && "Expected OpenMP device mode.");
+ const auto *D = cast<FunctionDecl>(OldGD.getDecl());
+
+ // Compute the function info and LLVM type.
+ const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(OldGD);
+ llvm::FunctionType *Ty = getTypes().GetFunctionType(FI);
+
+ // Get or create the prototype for the function.
+ if (!GV || (GV->getType()->getElementType() != Ty)) {
+ GV = cast<llvm::GlobalValue>(GetOrCreateLLVMFunction(
+ getMangledName(OldGD), Ty, GlobalDecl(), /*ForVTable=*/false,
+ /*DontDefer=*/true, /*IsThunk=*/false, llvm::AttributeList(),
+ ForDefinition));
+ SetFunctionAttributes(OldGD, cast<llvm::Function>(GV),
+ /*IsIncompleteFunction=*/false,
+ /*IsThunk=*/false);
+ }
+ // We need to set linkage and visibility on the function before
+ // generating code for it because various parts of IR generation
+ // want to propagate this information down (e.g. to local static
+ // declarations).
+ auto *Fn = cast<llvm::Function>(GV);
+ setFunctionLinkage(OldGD, Fn);
+
+ // FIXME: this is redundant with part of
+ // setFunctionDefinitionAttributes
+ setGVProperties(Fn, OldGD);
+
+ MaybeHandleStaticInExternC(D, Fn);
+
+ maybeSetTrivialComdat(*D, *Fn);
+
+ CodeGenFunction(*this).GenerateCode(NewGD, Fn, FI);
+
+ setNonAliasAttributes(OldGD, Fn);
+ SetLLVMFunctionAttributesForDefinition(D, Fn);
+
+ if (D->hasAttr<AnnotateAttr>())
+ AddGlobalAnnotations(D, Fn);
+}
+
void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) {
const auto *D = cast<ValueDecl>(GD.getDecl());
@@ -2816,11 +2882,13 @@ void CodeGenModule::emitMultiVersionFunctions() {
llvm::Function *ResolverFunc;
const TargetInfo &TI = getTarget();
- if (TI.supportsIFunc() || FD->isTargetMultiVersion())
+ if (TI.supportsIFunc() || FD->isTargetMultiVersion()) {
ResolverFunc = cast<llvm::Function>(
GetGlobalValue((getMangledName(GD) + ".resolver").str()));
- else
+ ResolverFunc->setLinkage(llvm::Function::WeakODRLinkage);
+ } else {
ResolverFunc = cast<llvm::Function>(GetGlobalValue(getMangledName(GD)));
+ }
if (supportsCOMDAT())
ResolverFunc->setComdat(
@@ -2864,6 +2932,10 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
auto *ResolverFunc = cast<llvm::Function>(GetOrCreateLLVMFunction(
ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false));
+ ResolverFunc->setLinkage(llvm::Function::WeakODRLinkage);
+ if (supportsCOMDAT())
+ ResolverFunc->setComdat(
+ getModule().getOrInsertComdat(ResolverFunc->getName()));
SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
const TargetInfo &Target = getTarget();
@@ -2928,6 +3000,21 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
CodeGenFunction CGF(*this);
CGF.EmitMultiVersionResolver(ResolverFunc, Options);
+
+ if (getTarget().supportsIFunc()) {
+ std::string AliasName = getMangledNameImpl(
+ *this, GD, FD, /*OmitMultiVersionMangling=*/true);
+ llvm::Constant *AliasFunc = GetGlobalValue(AliasName);
+ if (!AliasFunc) {
+ auto *IFunc = cast<llvm::GlobalIFunc>(GetOrCreateLLVMFunction(
+ AliasName, DeclTy, GD, /*ForVTable=*/false, /*DontDefer=*/true,
+ /*IsThunk=*/false, llvm::AttributeList(), NotForDefinition));
+ auto *GA = llvm::GlobalAlias::create(
+ DeclTy, 0, getFunctionLinkage(GD), AliasName, IFunc, &getModule());
+ GA->setLinkage(llvm::Function::WeakODRLinkage);
+ SetCommonAttributes(GD, GA);
+ }
+ }
}
/// If a dispatcher for the specified mangled name is not in the module, create
@@ -2964,7 +3051,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(
MangledName + ".resolver", ResolverType, GlobalDecl{},
/*ForVTable=*/false);
llvm::GlobalIFunc *GIF = llvm::GlobalIFunc::create(
- DeclTy, 0, llvm::Function::ExternalLinkage, "", Resolver, &getModule());
+ DeclTy, 0, llvm::Function::WeakODRLinkage, "", Resolver, &getModule());
GIF->setName(ResolverName);
SetCommonAttributes(FD, GIF);
@@ -3010,6 +3097,10 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
EmitGlobal(GDDef);
}
}
+ // Check if this must be emitted as declare variant and emit reference to
+ // the the declare variant function.
+ if (LangOpts.OpenMP && OpenMPRuntime)
+ (void)OpenMPRuntime->emitDeclareVariant(GD, /*IsForDefinition=*/true);
if (FD->isMultiVersion()) {
const auto *TA = FD->getAttr<TargetAttr>();
@@ -3398,7 +3489,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
// handling.
GV->setConstant(isTypeConstant(D->getType(), false));
- GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
+ GV->setAlignment(getContext().getDeclAlign(D).getAsAlign());
setLinkageForGV(GV, D);
@@ -3455,7 +3546,8 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
// Make a new global with the correct type, this is now guaranteed
// to work.
auto *NewGV = cast<llvm::GlobalVariable>(
- GetAddrOfGlobalVar(D, InitType, IsForDefinition));
+ GetAddrOfGlobalVar(D, InitType, IsForDefinition)
+ ->stripPointerCasts());
// Erase the old global, since it is no longer used.
GV->eraseFromParent();
@@ -3548,7 +3640,7 @@ llvm::GlobalVariable *CodeGenModule::CreateOrReplaceCXXRuntimeVariable(
!GV->hasAvailableExternallyLinkage())
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
- GV->setAlignment(Alignment);
+ GV->setAlignment(llvm::MaybeAlign(Alignment));
return GV;
}
@@ -3768,9 +3860,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
return;
llvm::Constant *Init = nullptr;
- CXXRecordDecl *RD = ASTTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
bool NeedsGlobalCtor = false;
- bool NeedsGlobalDtor = RD && !RD->hasTrivialDestructor();
+ bool NeedsGlobalDtor =
+ D->needsDestruction(getContext()) == QualType::DK_cxx_destructor;
const VarDecl *InitDecl;
const Expr *InitExpr = D->getAnyInitializer(InitDecl);
@@ -3837,14 +3929,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
llvm::Constant *Entry =
GetAddrOfGlobalVar(D, InitType, ForDefinition_t(!IsTentative));
- // Strip off a bitcast if we got one back.
- if (auto *CE = dyn_cast<llvm::ConstantExpr>(Entry)) {
- assert(CE->getOpcode() == llvm::Instruction::BitCast ||
- CE->getOpcode() == llvm::Instruction::AddrSpaceCast ||
- // All zero index gep.
- CE->getOpcode() == llvm::Instruction::GetElementPtr);
- Entry = CE->getOperand(0);
- }
+ // Strip off pointer casts if we got them.
+ Entry = Entry->stripPointerCasts();
// Entry is now either a Function or GlobalVariable.
auto *GV = dyn_cast<llvm::GlobalVariable>(Entry);
@@ -3867,7 +3953,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
// Make a new global with the correct type, this is now guaranteed to work.
GV = cast<llvm::GlobalVariable>(
- GetAddrOfGlobalVar(D, InitType, ForDefinition_t(!IsTentative)));
+ GetAddrOfGlobalVar(D, InitType, ForDefinition_t(!IsTentative))
+ ->stripPointerCasts());
// Replace all uses of the old global with the new global
llvm::Constant *NewPtrForOldDecl =
@@ -3944,8 +4031,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
GV->setConstant(true);
}
- GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
-
+ GV->setAlignment(getContext().getDeclAlign(D).getAsAlign());
// On Darwin, if the normal linkage of a C++ thread_local variable is
// LinkOnce or Weak, we keep the normal linkage to prevent multiple
@@ -4025,6 +4111,7 @@ static bool isVarDeclStrongDefinition(const ASTContext &Context,
// If no specialized section name is applicable, it will resort to default.
if (D->hasAttr<PragmaClangBSSSectionAttr>() ||
D->hasAttr<PragmaClangDataSectionAttr>() ||
+ D->hasAttr<PragmaClangRelroSectionAttr>() ||
D->hasAttr<PragmaClangRodataSectionAttr>())
return true;
@@ -4286,6 +4373,11 @@ void CodeGenModule::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
llvm::GlobalValue *GV) {
+ // Check if this must be emitted as declare variant.
+ if (LangOpts.OpenMP && OpenMPRuntime &&
+ OpenMPRuntime->emitDeclareVariant(GD, /*IsForDefinition=*/true))
+ return;
+
const auto *D = cast<FunctionDecl>(GD.getDecl());
// Compute the function info and LLVM type.
@@ -4355,17 +4447,22 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
// Create a reference to the named value. This ensures that it is emitted
// if a deferred decl.
llvm::Constant *Aliasee;
- if (isa<llvm::FunctionType>(DeclTy))
+ llvm::GlobalValue::LinkageTypes LT;
+ if (isa<llvm::FunctionType>(DeclTy)) {
Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GD,
/*ForVTable=*/false);
- else
+ LT = getFunctionLinkage(GD);
+ } else {
Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(),
llvm::PointerType::getUnqual(DeclTy),
/*D=*/nullptr);
+ LT = getLLVMLinkageVarDefinition(cast<VarDecl>(GD.getDecl()),
+ D->getType().isConstQualified());
+ }
// Create the new alias itself, but don't set a name yet.
- auto *GA = llvm::GlobalAlias::create(
- DeclTy, 0, llvm::Function::ExternalLinkage, "", Aliasee, &getModule());
+ auto *GA =
+ llvm::GlobalAlias::create(DeclTy, 0, LT, "", Aliasee, &getModule());
if (Entry) {
if (GA->getAliasee() == Entry) {
@@ -4634,7 +4731,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
// of the string is via this class initializer.
CharUnits Align = isUTF16 ? Context.getTypeAlignInChars(Context.ShortTy)
: Context.getTypeAlignInChars(Context.CharTy);
- GV->setAlignment(Align.getQuantity());
+ GV->setAlignment(Align.getAsAlign());
// FIXME: We set the section explicitly to avoid a bug in ld64 224.1.
// Without it LLVM can merge the string with a non unnamed_addr one during
@@ -4669,7 +4766,10 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
}
Fields.addInt(LengthTy, StringLength);
- CharUnits Alignment = getPointerAlign();
+ // Swift ABI requires 8-byte alignment to ensure that the _Atomic(uint64_t) is
+ // properly aligned on 32-bit platforms.
+ CharUnits Alignment =
+ IsSwiftABI ? Context.toCharUnitsFromBits(64) : getPointerAlign();
// The struct.
GV = Fields.finishAndCreateGlobal("_unnamed_cfstring_", Alignment,
@@ -4709,7 +4809,7 @@ QualType CodeGenModule::getObjCFastEnumerationStateType() {
Context.getPointerType(Context.getObjCIdType()),
Context.getPointerType(Context.UnsignedLongTy),
Context.getConstantArrayType(Context.UnsignedLongTy,
- llvm::APInt(32, 5), ArrayType::Normal, 0)
+ llvm::APInt(32, 5), nullptr, ArrayType::Normal, 0)
};
for (size_t i = 0; i < 4; ++i) {
@@ -4784,7 +4884,7 @@ GenerateStringLiteral(llvm::Constant *C, llvm::GlobalValue::LinkageTypes LT,
auto *GV = new llvm::GlobalVariable(
M, C->getType(), !CGM.getLangOpts().WritableStrings, LT, C, GlobalName,
nullptr, llvm::GlobalVariable::NotThreadLocal, AddrSpace);
- GV->setAlignment(Alignment.getQuantity());
+ GV->setAlignment(Alignment.getAsAlign());
GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
if (GV->isWeakForLinker()) {
assert(CGM.supportsCOMDAT() && "Only COFF uses weak string literals");
@@ -4808,7 +4908,7 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
Entry = &ConstantStringMap[C];
if (auto GV = *Entry) {
if (Alignment.getQuantity() > GV->getAlignment())
- GV->setAlignment(Alignment.getQuantity());
+ GV->setAlignment(Alignment.getAsAlign());
return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV),
Alignment);
}
@@ -4871,7 +4971,7 @@ ConstantAddress CodeGenModule::GetAddrOfConstantCString(
Entry = &ConstantStringMap[C];
if (auto GV = *Entry) {
if (Alignment.getQuantity() > GV->getAlignment())
- GV->setAlignment(Alignment.getQuantity());
+ GV->setAlignment(Alignment.getAsAlign());
return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV),
Alignment);
}
@@ -4916,14 +5016,13 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
VD, E->getManglingNumber(), Out);
APValue *Value = nullptr;
- if (E->getStorageDuration() == SD_Static) {
- // We might have a cached constant initializer for this temporary. Note
- // that this might have a different value from the value computed by
- // evaluating the initializer if the surrounding constant expression
- // modifies the temporary.
+ if (E->getStorageDuration() == SD_Static && VD && VD->evaluateValue()) {
+ // If the initializer of the extending declaration is a constant
+ // initializer, we should have a cached constant initializer for this
+ // temporary. Note that this might have a different value from the value
+ // computed by evaluating the initializer if the surrounding constant
+ // expression modifies the temporary.
Value = getContext().getMaterializedTemporaryValue(E, false);
- if (Value && Value->isAbsent())
- Value = nullptr;
}
// Try evaluating it now, it might have a constant initializer.
@@ -4974,7 +5073,7 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary(
/*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS);
if (emitter) emitter->finalize(GV);
setGVProperties(GV, VD);
- GV->setAlignment(Align.getQuantity());
+ GV->setAlignment(Align.getAsAlign());
if (supportsCOMDAT() && GV->isWeakForLinker())
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
if (VD->getTLSKind())
@@ -5083,7 +5182,9 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) {
// EmitLinkageSpec - Emit all declarations in a linkage spec.
void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) {
if (LSD->getLanguage() != LinkageSpecDecl::lang_c &&
- LSD->getLanguage() != LinkageSpecDecl::lang_cxx) {
+ LSD->getLanguage() != LinkageSpecDecl::lang_cxx &&
+ LSD->getLanguage() != LinkageSpecDecl::lang_cxx_11 &&
+ LSD->getLanguage() != LinkageSpecDecl::lang_cxx_14) {
ErrorUnsupported(LSD, "linkage spec");
return;
}
@@ -5804,7 +5905,7 @@ void CodeGenModule::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
llvm::SanitizerStatReport &CodeGenModule::getSanStats() {
if (!SanStats)
- SanStats = llvm::make_unique<llvm::SanitizerStatReport>(&getModule());
+ SanStats = std::make_unique<llvm::SanitizerStatReport>(&getModule());
return *SanStats;
}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 95964afed4ec..73f81adae35f 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -1270,13 +1270,26 @@ public:
/// \param D Requires declaration
void EmitOMPRequiresDecl(const OMPRequiresDecl *D);
+ /// Emits the definition of \p OldGD function with body from \p NewGD.
+ /// Required for proper handling of declare variant directive on the GPU.
+ void emitOpenMPDeviceFunctionRedefinition(GlobalDecl OldGD, GlobalDecl NewGD,
+ llvm::GlobalValue *GV);
+
/// Returns whether the given record has hidden LTO visibility and therefore
/// may participate in (single-module) CFI and whole-program vtable
/// optimization.
bool HasHiddenLTOVisibility(const CXXRecordDecl *RD);
+ /// Returns the vcall visibility of the given type. This is the scope in which
+ /// a virtual function call could be made which ends up being dispatched to a
+ /// member function of this class. This scope can be wider than the visibility
+ /// of the class itself when the class has a more-visible dynamic base class.
+ llvm::GlobalObject::VCallVisibility
+ GetVCallVisibilityLevel(const CXXRecordDecl *RD);
+
/// Emit type metadata for the given vtable using the given layout.
- void EmitVTableTypeMetadata(llvm::GlobalVariable *VTable,
+ void EmitVTableTypeMetadata(const CXXRecordDecl *RD,
+ llvm::GlobalVariable *VTable,
const VTableLayout &VTLayout);
/// Generate a cross-DSO type identifier for MD.
diff --git a/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp
index d10a321dc3d7..e525abe979e3 100644
--- a/lib/CodeGen/CodeGenPGO.cpp
+++ b/lib/CodeGen/CodeGenPGO.cpp
@@ -980,7 +980,7 @@ void CodeGenPGO::loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader,
return;
}
ProfRecord =
- llvm::make_unique<llvm::InstrProfRecord>(std::move(RecordExpected.get()));
+ std::make_unique<llvm::InstrProfRecord>(std::move(RecordExpected.get()));
RegionCounts = ProfRecord->Counts;
}
diff --git a/lib/CodeGen/CodeGenPGO.h b/lib/CodeGen/CodeGenPGO.h
index 2e740f789243..a3778b549910 100644
--- a/lib/CodeGen/CodeGenPGO.h
+++ b/lib/CodeGen/CodeGenPGO.h
@@ -41,8 +41,8 @@ private:
public:
CodeGenPGO(CodeGenModule &CGM)
- : CGM(CGM), NumValueSites({{0}}), NumRegionCounters(0), FunctionHash(0),
- CurrentRegionCount(0) {}
+ : CGM(CGM), FuncNameVar(nullptr), NumValueSites({{0}}),
+ NumRegionCounters(0), FunctionHash(0), CurrentRegionCount(0) {}
/// Whether or not we have PGO region data for the current function. This is
/// false both when we have no data at all and when our data has been
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 79b29b3d916f..a458811d7a30 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -135,8 +135,8 @@ isSafeToConvert(const RecordDecl *RD, CodeGenTypes &CGT,
// the class.
if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
for (const auto &I : CRD->bases())
- if (!isSafeToConvert(I.getType()->getAs<RecordType>()->getDecl(),
- CGT, AlreadyChecked))
+ if (!isSafeToConvert(I.getType()->castAs<RecordType>()->getDecl(), CGT,
+ AlreadyChecked))
return false;
}
@@ -402,7 +402,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("Non-canonical or dependent types aren't possible.");
case Type::Builtin: {
@@ -512,6 +512,22 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
ResultType = CGM.getOpenCLRuntime().convertOpenCLSpecificType(Ty);
break;
+ // TODO: real CodeGen support for SVE types requires more infrastructure
+ // to be added first. Report an error until then.
+#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
+ {
+ unsigned DiagID = CGM.getDiags().getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "cannot yet generate code for SVE type '%0'");
+ auto *BT = cast<BuiltinType>(Ty);
+ auto Name = BT->getName(CGM.getContext().getPrintingPolicy());
+ CGM.getDiags().Report(DiagID) << Name;
+ // Return something safe.
+ ResultType = llvm::IntegerType::get(getLLVMContext(), 32);
+ break;
+ }
+
case BuiltinType::Dependent:
#define BUILTIN_TYPE(Id, SingletonId)
#define PLACEHOLDER_TYPE(Id, SingletonId) \
@@ -728,8 +744,7 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) {
if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
for (const auto &I : CRD->bases()) {
if (I.isVirtual()) continue;
-
- ConvertRecordDeclType(I.getType()->getAs<RecordType>()->getDecl());
+ ConvertRecordDeclType(I.getType()->castAs<RecordType>()->getDecl());
}
}
diff --git a/lib/CodeGen/ConstantInitBuilder.cpp b/lib/CodeGen/ConstantInitBuilder.cpp
index 40b1607b5626..2d63d88020be 100644
--- a/lib/CodeGen/ConstantInitBuilder.cpp
+++ b/lib/CodeGen/ConstantInitBuilder.cpp
@@ -79,7 +79,7 @@ ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer,
/*insert before*/ nullptr,
llvm::GlobalValue::NotThreadLocal,
addressSpace);
- GV->setAlignment(alignment.getQuantity());
+ GV->setAlignment(alignment.getAsAlign());
resolveSelfReferences(GV);
return GV;
}
diff --git a/lib/CodeGen/CoverageMappingGen.cpp b/lib/CodeGen/CoverageMappingGen.cpp
index 6d18027f16a8..a6f6e38d5f14 100644
--- a/lib/CodeGen/CoverageMappingGen.cpp
+++ b/lib/CodeGen/CoverageMappingGen.cpp
@@ -1278,13 +1278,6 @@ std::string getCoverageSection(const CodeGenModule &CGM) {
CGM.getContext().getTargetInfo().getTriple().getObjectFormat());
}
-std::string normalizeFilename(StringRef Filename) {
- llvm::SmallString<256> Path(Filename);
- llvm::sys::fs::make_absolute(Path);
- llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
- return Path.str().str();
-}
-
} // end anonymous namespace
static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
@@ -1317,6 +1310,24 @@ static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
}
}
+CoverageMappingModuleGen::CoverageMappingModuleGen(
+ CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
+ : CGM(CGM), SourceInfo(SourceInfo), FunctionRecordTy(nullptr) {
+ // Honor -fdebug-compilation-dir in paths in coverage data. Otherwise, use the
+ // regular working directory when normalizing paths.
+ if (!CGM.getCodeGenOpts().DebugCompilationDir.empty())
+ CWD = CGM.getCodeGenOpts().DebugCompilationDir;
+ else
+ llvm::sys::fs::current_path(CWD);
+}
+
+std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
+ llvm::SmallString<256> Path(Filename);
+ llvm::sys::fs::make_absolute(CWD, Path);
+ llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
+ return Path.str().str();
+}
+
void CoverageMappingModuleGen::addFunctionMappingRecord(
llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
const std::string &CoverageMapping, bool IsUsed) {
@@ -1442,7 +1453,7 @@ void CoverageMappingModuleGen::emit() {
CovDataVal, llvm::getCoverageMappingVarName());
CovData->setSection(getCoverageSection(CGM));
- CovData->setAlignment(8);
+ CovData->setAlignment(llvm::Align(8));
// Make sure the data doesn't get deleted.
CGM.addUsedGlobal(CovData);
diff --git a/lib/CodeGen/CoverageMappingGen.h b/lib/CodeGen/CoverageMappingGen.h
index 3bf51f590479..2bdc00e25668 100644
--- a/lib/CodeGen/CoverageMappingGen.h
+++ b/lib/CodeGen/CoverageMappingGen.h
@@ -54,10 +54,14 @@ class CoverageMappingModuleGen {
std::vector<llvm::Constant *> FunctionNames;
llvm::StructType *FunctionRecordTy;
std::vector<std::string> CoverageMappings;
+ SmallString<256> CWD;
+
+ /// Make the filename absolute, remove dots, and normalize slashes to local
+ /// path style.
+ std::string normalizeFilename(StringRef Filename);
public:
- CoverageMappingModuleGen(CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
- : CGM(CGM), SourceInfo(SourceInfo), FunctionRecordTy(nullptr) {}
+ CoverageMappingModuleGen(CodeGenModule &CGM, CoverageSourceInfo &SourceInfo);
CoverageSourceInfo &getSourceInfo() const {
return SourceInfo;
diff --git a/lib/CodeGen/EHScopeStack.h b/lib/CodeGen/EHScopeStack.h
index 3b0db35d982b..0ed67aabcd62 100644
--- a/lib/CodeGen/EHScopeStack.h
+++ b/lib/CodeGen/EHScopeStack.h
@@ -199,14 +199,14 @@ public:
SavedTuple Saved;
template <std::size_t... Is>
- T restore(CodeGenFunction &CGF, llvm::index_sequence<Is...>) {
+ T restore(CodeGenFunction &CGF, std::index_sequence<Is...>) {
// It's important that the restores are emitted in order. The braced init
// list guarantees that.
return T{DominatingValue<As>::restore(CGF, std::get<Is>(Saved))...};
}
void Emit(CodeGenFunction &CGF, Flags flags) override {
- restore(CGF, llvm::index_sequence_for<As...>()).Emit(CGF, flags);
+ restore(CGF, std::index_sequence_for<As...>()).Emit(CGF, flags);
}
public:
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 3b2413d960d6..8f9b16470b64 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -43,6 +43,10 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
/// VTables - All the vtables which have been defined.
llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> VTables;
+ /// All the thread wrapper functions that have been used.
+ llvm::SmallVector<std::pair<const VarDecl *, llvm::Function *>, 8>
+ ThreadWrappers;
+
protected:
bool UseARMMethodPtrABI;
bool UseARMGuardVarABI;
@@ -322,7 +326,43 @@ public:
ArrayRef<llvm::Function *> CXXThreadLocalInits,
ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override;
- bool usesThreadWrapperFunction() const override { return true; }
+ /// Determine whether we will definitely emit this variable with a constant
+ /// initializer, either because the language semantics demand it or because
+ /// we know that the initializer is a constant.
+ bool isEmittedWithConstantInitializer(const VarDecl *VD) const {
+ VD = VD->getMostRecentDecl();
+ if (VD->hasAttr<ConstInitAttr>())
+ return true;
+
+ // All later checks examine the initializer specified on the variable. If
+ // the variable is weak, such examination would not be correct.
+ if (VD->isWeak() || VD->hasAttr<SelectAnyAttr>())
+ return false;
+
+ const VarDecl *InitDecl = VD->getInitializingDeclaration();
+ if (!InitDecl)
+ return false;
+
+ // If there's no initializer to run, this is constant initialization.
+ if (!InitDecl->hasInit())
+ return true;
+
+ // If we have the only definition, we don't need a thread wrapper if we
+ // will emit the value as a constant.
+ if (isUniqueGVALinkage(getContext().GetGVALinkageForVariable(VD)))
+ return !VD->needsDestruction(getContext()) && InitDecl->evaluateValue();
+
+ // Otherwise, we need a thread wrapper unless we know that every
+ // translation unit will emit the value as a constant. We rely on
+ // ICE-ness not varying between translation units, which isn't actually
+ // guaranteed by the standard but is necessary for sanity.
+ return InitDecl->isInitKnownICE() && InitDecl->isInitICE();
+ }
+
+ bool usesThreadWrapperFunction(const VarDecl *VD) const override {
+ return !isEmittedWithConstantInitializer(VD) ||
+ VD->needsDestruction(getContext());
+ }
LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
QualType LValType) override;
@@ -415,8 +455,8 @@ public:
class ARMCXXABI : public ItaniumCXXABI {
public:
ARMCXXABI(CodeGen::CodeGenModule &CGM) :
- ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true,
- /* UseARMGuardVarABI = */ true) {}
+ ItaniumCXXABI(CGM, /*UseARMMethodPtrABI=*/true,
+ /*UseARMGuardVarABI=*/true) {}
bool HasThisReturn(GlobalDecl GD) const override {
return (isa<CXXConstructorDecl>(GD.getDecl()) || (
@@ -480,11 +520,11 @@ CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) {
// include the other 32-bit ARM oddities: constructor/destructor return values
// and array cookies.
case TargetCXXABI::GenericAArch64:
- return new ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true,
- /* UseARMGuardVarABI = */ true);
+ return new ItaniumCXXABI(CGM, /*UseARMMethodPtrABI=*/true,
+ /*UseARMGuardVarABI=*/true);
case TargetCXXABI::GenericMIPS:
- return new ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true);
+ return new ItaniumCXXABI(CGM, /*UseARMMethodPtrABI=*/true);
case TargetCXXABI::WebAssembly:
return new WebAssemblyCXXABI(CGM);
@@ -495,8 +535,7 @@ CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) {
// For PNaCl, use ARM-style method pointers so that PNaCl code
// does not assume anything about the alignment of function
// pointers.
- return new ItaniumCXXABI(CGM, /* UseARMMethodPtrABI = */ true,
- /* UseARMGuardVarABI = */ false);
+ return new ItaniumCXXABI(CGM, /*UseARMMethodPtrABI=*/true);
}
return new ItaniumCXXABI(CGM);
@@ -541,8 +580,8 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
const FunctionProtoType *FPT =
MPT->getPointeeType()->getAs<FunctionProtoType>();
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
+ auto *RD =
+ cast<CXXRecordDecl>(MPT->getClass()->castAs<RecordType>()->getDecl());
llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(
CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr));
@@ -605,8 +644,6 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
VTableOffset = Builder.CreateTrunc(VTableOffset, CGF.Int32Ty);
VTableOffset = Builder.CreateZExt(VTableOffset, CGM.PtrDiffTy);
}
- // Compute the address of the virtual function pointer.
- llvm::Value *VFPAddr = Builder.CreateGEP(VTable, VTableOffset);
// Check the address of the function pointer if CFI on member function
// pointers is enabled.
@@ -614,44 +651,81 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
llvm::Constant *CheckTypeDesc;
bool ShouldEmitCFICheck = CGF.SanOpts.has(SanitizerKind::CFIMFCall) &&
CGM.HasHiddenLTOVisibility(RD);
- if (ShouldEmitCFICheck) {
- CodeGenFunction::SanitizerScope SanScope(&CGF);
-
- CheckSourceLocation = CGF.EmitCheckSourceLocation(E->getBeginLoc());
- CheckTypeDesc = CGF.EmitCheckTypeDescriptor(QualType(MPT, 0));
- llvm::Constant *StaticData[] = {
- llvm::ConstantInt::get(CGF.Int8Ty, CodeGenFunction::CFITCK_VMFCall),
- CheckSourceLocation,
- CheckTypeDesc,
- };
-
- llvm::Metadata *MD =
- CGM.CreateMetadataIdentifierForVirtualMemPtrType(QualType(MPT, 0));
- llvm::Value *TypeId = llvm::MetadataAsValue::get(CGF.getLLVMContext(), MD);
+ bool ShouldEmitVFEInfo = CGM.getCodeGenOpts().VirtualFunctionElimination &&
+ CGM.HasHiddenLTOVisibility(RD);
+ llvm::Value *VirtualFn = nullptr;
- llvm::Value *TypeTest = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::type_test), {VFPAddr, TypeId});
+ {
+ CodeGenFunction::SanitizerScope SanScope(&CGF);
+ llvm::Value *TypeId = nullptr;
+ llvm::Value *CheckResult = nullptr;
+
+ if (ShouldEmitCFICheck || ShouldEmitVFEInfo) {
+ // If doing CFI or VFE, we will need the metadata node to check against.
+ llvm::Metadata *MD =
+ CGM.CreateMetadataIdentifierForVirtualMemPtrType(QualType(MPT, 0));
+ TypeId = llvm::MetadataAsValue::get(CGF.getLLVMContext(), MD);
+ }
- if (CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIMFCall)) {
- CGF.EmitTrapCheck(TypeTest);
+ llvm::Value *VFPAddr = Builder.CreateGEP(VTable, VTableOffset);
+
+ if (ShouldEmitVFEInfo) {
+ // If doing VFE, load from the vtable with a type.checked.load intrinsic
+ // call. Note that we use the GEP to calculate the address to load from
+ // and pass 0 as the offset to the intrinsic. This is because every
+ // vtable slot of the correct type is marked with matching metadata, and
+ // we know that the load must be from one of these slots.
+ llvm::Value *CheckedLoad = Builder.CreateCall(
+ CGM.getIntrinsic(llvm::Intrinsic::type_checked_load),
+ {VFPAddr, llvm::ConstantInt::get(CGM.Int32Ty, 0), TypeId});
+ CheckResult = Builder.CreateExtractValue(CheckedLoad, 1);
+ VirtualFn = Builder.CreateExtractValue(CheckedLoad, 0);
+ VirtualFn = Builder.CreateBitCast(VirtualFn, FTy->getPointerTo(),
+ "memptr.virtualfn");
} else {
- llvm::Value *AllVtables = llvm::MetadataAsValue::get(
- CGM.getLLVMContext(),
- llvm::MDString::get(CGM.getLLVMContext(), "all-vtables"));
- llvm::Value *ValidVtable = Builder.CreateCall(
- CGM.getIntrinsic(llvm::Intrinsic::type_test), {VTable, AllVtables});
- CGF.EmitCheck(std::make_pair(TypeTest, SanitizerKind::CFIMFCall),
- SanitizerHandler::CFICheckFail, StaticData,
- {VTable, ValidVtable});
+ // When not doing VFE, emit a normal load, as it allows more
+ // optimisations than type.checked.load.
+ if (ShouldEmitCFICheck) {
+ CheckResult = Builder.CreateCall(
+ CGM.getIntrinsic(llvm::Intrinsic::type_test),
+ {Builder.CreateBitCast(VFPAddr, CGF.Int8PtrTy), TypeId});
+ }
+ VFPAddr =
+ Builder.CreateBitCast(VFPAddr, FTy->getPointerTo()->getPointerTo());
+ VirtualFn = Builder.CreateAlignedLoad(VFPAddr, CGF.getPointerAlign(),
+ "memptr.virtualfn");
}
+ assert(VirtualFn && "Virtual fuction pointer not created!");
+ assert((!ShouldEmitCFICheck || !ShouldEmitVFEInfo || CheckResult) &&
+ "Check result required but not created!");
+
+ if (ShouldEmitCFICheck) {
+ // If doing CFI, emit the check.
+ CheckSourceLocation = CGF.EmitCheckSourceLocation(E->getBeginLoc());
+ CheckTypeDesc = CGF.EmitCheckTypeDescriptor(QualType(MPT, 0));
+ llvm::Constant *StaticData[] = {
+ llvm::ConstantInt::get(CGF.Int8Ty, CodeGenFunction::CFITCK_VMFCall),
+ CheckSourceLocation,
+ CheckTypeDesc,
+ };
- FnVirtual = Builder.GetInsertBlock();
- }
+ if (CGM.getCodeGenOpts().SanitizeTrap.has(SanitizerKind::CFIMFCall)) {
+ CGF.EmitTrapCheck(CheckResult);
+ } else {
+ llvm::Value *AllVtables = llvm::MetadataAsValue::get(
+ CGM.getLLVMContext(),
+ llvm::MDString::get(CGM.getLLVMContext(), "all-vtables"));
+ llvm::Value *ValidVtable = Builder.CreateCall(
+ CGM.getIntrinsic(llvm::Intrinsic::type_test), {VTable, AllVtables});
+ CGF.EmitCheck(std::make_pair(CheckResult, SanitizerKind::CFIMFCall),
+ SanitizerHandler::CFICheckFail, StaticData,
+ {VTable, ValidVtable});
+ }
+
+ FnVirtual = Builder.GetInsertBlock();
+ }
+ } // End of sanitizer scope
- // Load the virtual function to call.
- VFPAddr = Builder.CreateBitCast(VFPAddr, FTy->getPointerTo()->getPointerTo());
- llvm::Value *VirtualFn = Builder.CreateAlignedLoad(
- VFPAddr, CGF.getPointerAlign(), "memptr.virtualfn");
CGF.EmitBranch(FnEnd);
// In the non-virtual path, the function pointer is actually a
@@ -1104,7 +1178,7 @@ void ItaniumCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF,
// Grab the vtable pointer as an intptr_t*.
auto *ClassDecl =
- cast<CXXRecordDecl>(ElementType->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(ElementType->castAs<RecordType>()->getDecl());
llvm::Value *VTable =
CGF.GetVTablePtr(Ptr, CGF.IntPtrTy->getPointerTo(), ClassDecl);
@@ -1307,7 +1381,7 @@ llvm::Value *ItaniumCXXABI::EmitTypeid(CodeGenFunction &CGF,
Address ThisPtr,
llvm::Type *StdTypeInfoPtrTy) {
auto *ClassDecl =
- cast<CXXRecordDecl>(SrcRecordTy->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(SrcRecordTy->castAs<RecordType>()->getDecl());
llvm::Value *Value =
CGF.GetVTablePtr(ThisPtr, StdTypeInfoPtrTy->getPointerTo(), ClassDecl);
@@ -1373,7 +1447,7 @@ llvm::Value *ItaniumCXXABI::EmitDynamicCastToVoid(CodeGenFunction &CGF,
llvm::Type *DestLTy = CGF.ConvertType(DestTy);
auto *ClassDecl =
- cast<CXXRecordDecl>(SrcRecordTy->getAs<RecordType>()->getDecl());
+ cast<CXXRecordDecl>(SrcRecordTy->castAs<RecordType>()->getDecl());
// Get the vtable pointer.
llvm::Value *VTable = CGF.GetVTablePtr(ThisAddr, PtrDiffLTy->getPointerTo(),
ClassDecl);
@@ -1595,7 +1669,7 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
EmitFundamentalRTTIDescriptors(RD);
if (!VTable->isDeclarationForLinker())
- CGM.EmitVTableTypeMetadata(VTable, VTLayout);
+ CGM.EmitVTableTypeMetadata(RD, VTable, VTLayout);
}
bool ItaniumCXXABI::isVirtualOffsetNeededForVTableField(
@@ -1755,10 +1829,11 @@ llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall(
CGCallee Callee = CGCallee::forVirtual(CE, GD, This, Ty);
QualType ThisTy;
- if (CE)
- ThisTy = CE->getImplicitObjectArgument()->getType()->getPointeeType();
- else
+ if (CE) {
+ ThisTy = CE->getObjectType();
+ } else {
ThisTy = D->getDestroyedType();
+ }
CGF.EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy, nullptr,
QualType(), nullptr);
@@ -2154,7 +2229,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
guard->setVisibility(var->getVisibility());
// If the variable is thread-local, so is its guard variable.
guard->setThreadLocalMode(var->getThreadLocalMode());
- guard->setAlignment(guardAlignment.getQuantity());
+ guard->setAlignment(guardAlignment.getAsAlign());
// The ABI says: "It is suggested that it be emitted in the same COMDAT
// group as the associated data object." In practice, this doesn't work for
@@ -2456,9 +2531,6 @@ ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI, Wrapper);
- if (VD->hasDefinition())
- CGM.SetLLVMFunctionAttributesForDefinition(nullptr, Wrapper);
-
// Always resolve references to the wrapper at link time.
if (!Wrapper->hasLocalLinkage())
if (!isThreadWrapperReplaceable(VD, CGM) ||
@@ -2471,6 +2543,8 @@ ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
Wrapper->setCallingConv(llvm::CallingConv::CXX_FAST_TLS);
Wrapper->addFnAttr(llvm::Attribute::NoUnwind);
}
+
+ ThreadWrappers.push_back({VD, Wrapper});
return Wrapper;
}
@@ -2508,7 +2582,7 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
Guard->setThreadLocal(true);
CharUnits GuardAlign = CharUnits::One();
- Guard->setAlignment(GuardAlign.getQuantity());
+ Guard->setAlignment(GuardAlign.getAsAlign());
CodeGenFunction(CGM).GenerateCXXGlobalInitFunc(
InitFunc, OrderedInits, ConstantAddress(Guard, GuardAlign));
@@ -2519,20 +2593,40 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
}
}
- // Emit thread wrappers.
+ // Create declarations for thread wrappers for all thread-local variables
+ // with non-discardable definitions in this translation unit.
for (const VarDecl *VD : CXXThreadLocals) {
+ if (VD->hasDefinition() &&
+ !isDiscardableGVALinkage(getContext().GetGVALinkageForVariable(VD))) {
+ llvm::GlobalValue *GV = CGM.GetGlobalValue(CGM.getMangledName(VD));
+ getOrCreateThreadLocalWrapper(VD, GV);
+ }
+ }
+
+ // Emit all referenced thread wrappers.
+ for (auto VDAndWrapper : ThreadWrappers) {
+ const VarDecl *VD = VDAndWrapper.first;
llvm::GlobalVariable *Var =
cast<llvm::GlobalVariable>(CGM.GetGlobalValue(CGM.getMangledName(VD)));
- llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Var);
+ llvm::Function *Wrapper = VDAndWrapper.second;
// Some targets require that all access to thread local variables go through
// the thread wrapper. This means that we cannot attempt to create a thread
// wrapper or a thread helper.
- if (isThreadWrapperReplaceable(VD, CGM) && !VD->hasDefinition()) {
- Wrapper->setLinkage(llvm::Function::ExternalLinkage);
- continue;
+ if (!VD->hasDefinition()) {
+ if (isThreadWrapperReplaceable(VD, CGM)) {
+ Wrapper->setLinkage(llvm::Function::ExternalLinkage);
+ continue;
+ }
+
+ // If this isn't a TU in which this variable is defined, the thread
+ // wrapper is discardable.
+ if (Wrapper->getLinkage() == llvm::Function::WeakODRLinkage)
+ Wrapper->setLinkage(llvm::Function::LinkOnceODRLinkage);
}
+ CGM.SetLLVMFunctionAttributesForDefinition(nullptr, Wrapper);
+
// Mangle the name for the thread_local initialization function.
SmallString<256> InitFnName;
{
@@ -2547,7 +2641,10 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
// produce a declaration of the initialization function.
llvm::GlobalValue *Init = nullptr;
bool InitIsInitFunc = false;
- if (VD->hasDefinition()) {
+ bool HasConstantInitialization = false;
+ if (!usesThreadWrapperFunction(VD)) {
+ HasConstantInitialization = true;
+ } else if (VD->hasDefinition()) {
InitIsInitFunc = true;
llvm::Function *InitFuncToUse = InitFunc;
if (isTemplateInstantiation(VD->getTemplateSpecializationKind()))
@@ -2576,7 +2673,9 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs(
llvm::LLVMContext &Context = CGM.getModule().getContext();
llvm::BasicBlock *Entry = llvm::BasicBlock::Create(Context, "", Wrapper);
CGBuilderTy Builder(CGM, Entry);
- if (InitIsInitFunc) {
+ if (HasConstantInitialization) {
+ // No dynamic initialization to invoke.
+ } else if (InitIsInitFunc) {
if (Init) {
llvm::CallInst *CallVal = Builder.CreateCall(InitFnTy, Init);
if (isThreadWrapperReplaceable(VD, CGM)) {
@@ -2860,6 +2959,9 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
case BuiltinType::OCLReserveID:
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
case BuiltinType::ShortAccum:
case BuiltinType::Accum:
case BuiltinType::LongAccum:
@@ -3033,8 +3135,8 @@ static bool CanUseSingleInheritance(const CXXRecordDecl *RD) {
return false;
// Check that the class is dynamic iff the base is.
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ auto *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->castAs<RecordType>()->getDecl());
if (!BaseDecl->isEmpty() &&
BaseDecl->isDynamicClass() != RD->isDynamicClass())
return false;
@@ -3061,7 +3163,7 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("Non-canonical and dependent types shouldn't get here");
case Type::LValueReference:
@@ -3307,7 +3409,7 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
llvm_unreachable("Non-canonical and dependent types shouldn't get here");
// GCC treats vector types as fundamental types.
@@ -3412,7 +3514,7 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
CharUnits Align =
CGM.getContext().toCharUnitsFromBits(CGM.getTarget().getPointerAlign(0));
- GV->setAlignment(Align.getQuantity());
+ GV->setAlignment(Align.getAsAlign());
// The Itanium ABI specifies that type_info objects must be globally
// unique, with one exception: if the type is an incomplete class
@@ -3497,8 +3599,8 @@ static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
unsigned Flags = 0;
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ auto *BaseDecl =
+ cast<CXXRecordDecl>(Base->getType()->castAs<RecordType>()->getDecl());
if (Base->isVirtual()) {
// Mark the virtual base as seen.
@@ -3596,8 +3698,8 @@ void ItaniumRTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
// The __base_type member points to the RTTI for the base type.
Fields.push_back(ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(Base.getType()));
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+ auto *BaseDecl =
+ cast<CXXRecordDecl>(Base.getType()->castAs<RecordType>()->getDecl());
int64_t OffsetFlags = 0;
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index fa34414de5da..2d8b538bc2ee 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -386,7 +386,9 @@ public:
ArrayRef<llvm::Function *> CXXThreadLocalInits,
ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override;
- bool usesThreadWrapperFunction() const override { return false; }
+ bool usesThreadWrapperFunction(const VarDecl *VD) const override {
+ return false;
+ }
LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
QualType LValType) override;
@@ -1208,7 +1210,7 @@ static bool hasDefaultCXXMethodCC(ASTContext &Context,
CallingConv ExpectedCallingConv = Context.getDefaultCallingConvention(
/*IsVariadic=*/false, /*IsCXXMethod=*/true);
CallingConv ActualCallingConv =
- MD->getType()->getAs<FunctionProtoType>()->getCallConv();
+ MD->getType()->castAs<FunctionProtoType>()->getCallConv();
return ExpectedCallingConv == ActualCallingConv;
}
@@ -1921,10 +1923,11 @@ llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall(
DtorType == Dtor_Deleting);
QualType ThisTy;
- if (CE)
- ThisTy = CE->getImplicitObjectArgument()->getType()->getPointeeType();
- else
+ if (CE) {
+ ThisTy = CE->getObjectType();
+ } else {
ThisTy = D->getDestroyedType();
+ }
This = adjustThisArgumentForVirtualFunctionCall(CGF, GD, This, true);
RValue RV = CGF.EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy,
@@ -2352,7 +2355,7 @@ static ConstantAddress getInitThreadEpochPtr(CodeGenModule &CGM) {
/*isConstant=*/false, llvm::GlobalVariable::ExternalLinkage,
/*Initializer=*/nullptr, VarName,
/*InsertBefore=*/nullptr, llvm::GlobalVariable::GeneralDynamicTLSModel);
- GV->setAlignment(Align.getQuantity());
+ GV->setAlignment(Align.getAsAlign());
return ConstantAddress(GV, Align);
}
@@ -2495,7 +2498,7 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
GV->getLinkage(), Zero, GuardName.str());
GuardVar->setVisibility(GV->getVisibility());
GuardVar->setDLLStorageClass(GV->getDLLStorageClass());
- GuardVar->setAlignment(GuardAlign.getQuantity());
+ GuardVar->setAlignment(GuardAlign.getAsAlign());
if (GuardVar->isWeakForLinker())
GuardVar->setComdat(
CGM.getModule().getOrInsertComdat(GuardVar->getName()));
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 3b4e06045a37..4154f6ebe736 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -65,6 +65,13 @@ namespace {
private:
SmallVector<FunctionDecl *, 8> DeferredInlineMemberFuncDefs;
+ static llvm::StringRef ExpandModuleName(llvm::StringRef ModuleName,
+ const CodeGenOptions &CGO) {
+ if (ModuleName == "-" && !CGO.MainFileName.empty())
+ return CGO.MainFileName;
+ return ModuleName;
+ }
+
public:
CodeGeneratorImpl(DiagnosticsEngine &diags, llvm::StringRef ModuleName,
const HeaderSearchOptions &HSO,
@@ -73,7 +80,8 @@ namespace {
CoverageSourceInfo *CoverageInfo = nullptr)
: Diags(diags), Ctx(nullptr), HeaderSearchOpts(HSO),
PreprocessorOpts(PPO), CodeGenOpts(CGO), HandlingTopLevelDecls(0),
- CoverageInfo(CoverageInfo), M(new llvm::Module(ModuleName, C)) {
+ CoverageInfo(CoverageInfo),
+ M(new llvm::Module(ExpandModuleName(ModuleName, CGO), C)) {
C.setDiscardValueNames(CGO.DiscardValueNames);
}
@@ -121,7 +129,7 @@ namespace {
llvm::Module *StartModule(llvm::StringRef ModuleName,
llvm::LLVMContext &C) {
assert(!M && "Replacing existing Module?");
- M.reset(new llvm::Module(ModuleName, C));
+ M.reset(new llvm::Module(ExpandModuleName(ModuleName, CodeGenOpts), C));
Initialize(*Ctx);
return M.get();
}
@@ -232,6 +240,9 @@ namespace {
if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(Member)) {
if (Ctx->DeclMustBeEmitted(DRD))
Builder->EmitGlobal(DRD);
+ } else if (auto *DMD = dyn_cast<OMPDeclareMapperDecl>(Member)) {
+ if (Ctx->DeclMustBeEmitted(DMD))
+ Builder->EmitGlobal(DMD);
}
}
}
diff --git a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
index 15a2ab99fdac..284e8022a3c4 100644
--- a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
+++ b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
@@ -279,7 +279,7 @@ public:
*M, Ty, /*constant*/ true, llvm::GlobalVariable::InternalLinkage, Data,
"__clang_ast");
// The on-disk hashtable needs to be aligned.
- ASTSym->setAlignment(8);
+ ASTSym->setAlignment(llvm::Align(8));
// Mach-O also needs a segment name.
if (Triple.isOSBinFormatMachO())
@@ -297,7 +297,7 @@ public:
Diags, HeaderSearchOpts, CodeGenOpts, TargetOpts, LangOpts,
Ctx.getTargetInfo().getDataLayout(), M.get(),
BackendAction::Backend_EmitLL,
- llvm::make_unique<llvm::raw_svector_ostream>(Buffer));
+ std::make_unique<llvm::raw_svector_ostream>(Buffer));
llvm::dbgs() << Buffer;
});
@@ -321,7 +321,7 @@ ObjectFilePCHContainerWriter::CreatePCHContainerGenerator(
const std::string &OutputFileName,
std::unique_ptr<llvm::raw_pwrite_stream> OS,
std::shared_ptr<PCHBuffer> Buffer) const {
- return llvm::make_unique<PCHContainerGenerator>(
+ return std::make_unique<PCHContainerGenerator>(
CI, MainFileName, OutputFileName, std::move(OS), Buffer);
}
@@ -335,7 +335,11 @@ ObjectFilePCHContainerReader::ExtractPCH(llvm::MemoryBufferRef Buffer) const {
// Find the clang AST section in the container.
for (auto &Section : OF->sections()) {
StringRef Name;
- Section.getName(Name);
+ if (Expected<StringRef> NameOrErr = Section.getName())
+ Name = *NameOrErr;
+ else
+ consumeError(NameOrErr.takeError());
+
if ((!IsCOFF && Name == "__clangast") || (IsCOFF && Name == "clangast")) {
if (Expected<StringRef> E = Section.getContents())
return *E;
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 5da988fb8a3c..c2c7b8bf653b 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -833,10 +833,13 @@ ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const {
Address WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
QualType Ty) const {
- return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*IsIndirect=*/ false,
+ bool IsIndirect = isAggregateTypeForABI(Ty) &&
+ !isEmptyRecord(getContext(), Ty, true) &&
+ !isSingleElementStruct(Ty, getContext());
+ return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect,
getContext().getTypeInfoInChars(Ty),
CharUnits::fromQuantity(4),
- /*AllowHigherAlign=*/ true);
+ /*AllowHigherAlign=*/true);
}
//===----------------------------------------------------------------------===//
@@ -2177,6 +2180,17 @@ class X86_64ABIInfo : public SwiftABIInfo {
return true;
}
+ // GCC classifies vectors of __int128 as memory.
+ bool passInt128VectorsInMem() const {
+ // Clang <= 9.0 did not do this.
+ if (getContext().getLangOpts().getClangABICompat() <=
+ LangOptions::ClangABI::Ver9)
+ return false;
+
+ const llvm::Triple &T = getTarget().getTriple();
+ return T.isOSLinux() || T.isOSNetBSD();
+ }
+
X86AVXABILevel AVXLevel;
// Some ABIs (e.g. X32 ABI and Native Client OS) use 32 bit pointers on
// 64-bit hardware.
@@ -2657,6 +2671,14 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
Hi = Lo;
} else if (Size == 128 ||
(isNamedArg && Size <= getNativeVectorSizeForAVXABI(AVXLevel))) {
+ QualType ElementType = VT->getElementType();
+
+ // gcc passes 256 and 512 bit <X x __int128> vectors in memory. :(
+ if (passInt128VectorsInMem() && Size != 128 &&
+ (ElementType->isSpecificBuiltinType(BuiltinType::Int128) ||
+ ElementType->isSpecificBuiltinType(BuiltinType::UInt128)))
+ return;
+
// 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
@@ -2787,8 +2809,8 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
for (const auto &I : CXXRD->bases()) {
assert(!I.isVirtual() && !I.getType()->isDependentType() &&
"Unexpected base class!");
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const auto *Base =
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
// Classify this field.
//
@@ -2899,6 +2921,11 @@ bool X86_64ABIInfo::IsIllegalVectorType(QualType Ty) const {
unsigned LargestVector = getNativeVectorSizeForAVXABI(AVXLevel);
if (Size <= 64 || Size > LargestVector)
return true;
+ QualType EltTy = VecTy->getElementType();
+ if (passInt128VectorsInMem() &&
+ (EltTy->isSpecificBuiltinType(BuiltinType::Int128) ||
+ EltTy->isSpecificBuiltinType(BuiltinType::UInt128)))
+ return true;
}
return false;
@@ -2973,14 +3000,28 @@ llvm::Type *X86_64ABIInfo::GetByteVectorType(QualType Ty) const {
Ty = QualType(InnerTy, 0);
llvm::Type *IRType = CGT.ConvertType(Ty);
- if (isa<llvm::VectorType>(IRType) ||
- IRType->getTypeID() == llvm::Type::FP128TyID)
+ if (isa<llvm::VectorType>(IRType)) {
+ // Don't pass vXi128 vectors in their native type, the backend can't
+ // legalize them.
+ if (passInt128VectorsInMem() &&
+ IRType->getVectorElementType()->isIntegerTy(128)) {
+ // Use a vXi64 vector.
+ uint64_t Size = getContext().getTypeSize(Ty);
+ return llvm::VectorType::get(llvm::Type::getInt64Ty(getVMContext()),
+ Size / 64);
+ }
+
+ return IRType;
+ }
+
+ if (IRType->getTypeID() == llvm::Type::FP128TyID)
return IRType;
// We couldn't find the preferred IR vector type for 'Ty'.
uint64_t Size = getContext().getTypeSize(Ty);
assert((Size == 128 || Size == 256 || Size == 512) && "Invalid type found!");
+
// Return a LLVM IR vector type based on the size of 'Ty'.
return llvm::VectorType::get(llvm::Type::getDoubleTy(getVMContext()),
Size / 64);
@@ -3030,8 +3071,8 @@ static bool BitsContainNoUserData(QualType Ty, unsigned StartBit,
for (const auto &I : CXXRD->bases()) {
assert(!I.isVirtual() && !I.getType()->isDependentType() &&
"Unexpected base class!");
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const auto *Base =
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
// If the base is after the span we care about, ignore it.
unsigned BaseOffset = Context.toBits(Layout.getBaseClassOffset(Base));
@@ -7909,8 +7950,12 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes(
const auto *ReqdWGS = M.getLangOpts().OpenCL ?
FD->getAttr<ReqdWorkGroupSizeAttr>() : nullptr;
- if (((M.getLangOpts().OpenCL && FD->hasAttr<OpenCLKernelAttr>()) ||
- (M.getLangOpts().HIP && FD->hasAttr<CUDAGlobalAttr>())) &&
+
+ const bool IsOpenCLKernel = M.getLangOpts().OpenCL &&
+ FD->hasAttr<OpenCLKernelAttr>();
+ const bool IsHIPKernel = M.getLangOpts().HIP &&
+ FD->hasAttr<CUDAGlobalAttr>();
+ if ((IsOpenCLKernel || IsHIPKernel) &&
(M.getTriple().getOS() == llvm::Triple::AMDHSA))
F->addFnAttr("amdgpu-implicitarg-num-bytes", "56");
@@ -7936,6 +7981,9 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes(
F->addFnAttr("amdgpu-flat-work-group-size", AttrVal);
} else
assert(Max == 0 && "Max must be zero");
+ } else if (IsOpenCLKernel || IsHIPKernel) {
+ // By default, restrict the maximum size to 256.
+ F->addFnAttr("amdgpu-flat-work-group-size", "1,256");
}
if (const auto *Attr = FD->getAttr<AMDGPUWavesPerEUAttr>()) {
@@ -9188,25 +9236,45 @@ static bool getTypeString(SmallStringEnc &Enc, const Decl *D,
namespace {
class RISCVABIInfo : public DefaultABIInfo {
private:
- unsigned XLen; // Size of the integer ('x') registers in bits.
+ // Size of the integer ('x') registers in bits.
+ unsigned XLen;
+ // Size of the floating point ('f') registers in bits. Note that the target
+ // ISA might have a wider FLen than the selected ABI (e.g. an RV32IF target
+ // with soft float ABI has FLen==0).
+ unsigned FLen;
static const int NumArgGPRs = 8;
+ static const int NumArgFPRs = 8;
+ bool detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff,
+ llvm::Type *&Field1Ty,
+ CharUnits &Field1Off,
+ llvm::Type *&Field2Ty,
+ CharUnits &Field2Off) const;
public:
- RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen)
- : DefaultABIInfo(CGT), XLen(XLen) {}
+ RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen)
+ : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen) {}
// DefaultABIInfo's classifyReturnType and classifyArgumentType are
// non-virtual, but computeInfo is virtual, so we overload it.
void computeInfo(CGFunctionInfo &FI) const override;
- ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed,
- int &ArgGPRsLeft) const;
+ ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &ArgGPRsLeft,
+ int &ArgFPRsLeft) const;
ABIArgInfo classifyReturnType(QualType RetTy) const;
Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
QualType Ty) const override;
ABIArgInfo extendType(QualType Ty) const;
+
+ bool detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty,
+ CharUnits &Field1Off, llvm::Type *&Field2Ty,
+ CharUnits &Field2Off, int &NeededArgGPRs,
+ int &NeededArgFPRs) const;
+ ABIArgInfo coerceAndExpandFPCCEligibleStruct(llvm::Type *Field1Ty,
+ CharUnits Field1Off,
+ llvm::Type *Field2Ty,
+ CharUnits Field2Off) const;
};
} // end anonymous namespace
@@ -9228,18 +9296,215 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const {
// different for variadic arguments, we must also track whether we are
// examining a vararg or not.
int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs;
+ int ArgFPRsLeft = FLen ? NumArgFPRs : 0;
int NumFixedArgs = FI.getNumRequiredArgs();
int ArgNum = 0;
for (auto &ArgInfo : FI.arguments()) {
bool IsFixed = ArgNum < NumFixedArgs;
- ArgInfo.info = classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft);
+ ArgInfo.info =
+ classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft, ArgFPRsLeft);
ArgNum++;
}
}
+// Returns true if the struct is a potential candidate for the floating point
+// calling convention. If this function returns true, the caller is
+// responsible for checking that if there is only a single field then that
+// field is a float.
+bool RISCVABIInfo::detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff,
+ llvm::Type *&Field1Ty,
+ CharUnits &Field1Off,
+ llvm::Type *&Field2Ty,
+ CharUnits &Field2Off) const {
+ bool IsInt = Ty->isIntegralOrEnumerationType();
+ bool IsFloat = Ty->isRealFloatingType();
+
+ if (IsInt || IsFloat) {
+ uint64_t Size = getContext().getTypeSize(Ty);
+ if (IsInt && Size > XLen)
+ return false;
+ // Can't be eligible if larger than the FP registers. Half precision isn't
+ // currently supported on RISC-V and the ABI hasn't been confirmed, so
+ // default to the integer ABI in that case.
+ if (IsFloat && (Size > FLen || Size < 32))
+ return false;
+ // Can't be eligible if an integer type was already found (int+int pairs
+ // are not eligible).
+ if (IsInt && Field1Ty && Field1Ty->isIntegerTy())
+ return false;
+ if (!Field1Ty) {
+ Field1Ty = CGT.ConvertType(Ty);
+ Field1Off = CurOff;
+ return true;
+ }
+ if (!Field2Ty) {
+ Field2Ty = CGT.ConvertType(Ty);
+ Field2Off = CurOff;
+ return true;
+ }
+ return false;
+ }
+
+ if (auto CTy = Ty->getAs<ComplexType>()) {
+ if (Field1Ty)
+ return false;
+ QualType EltTy = CTy->getElementType();
+ if (getContext().getTypeSize(EltTy) > FLen)
+ return false;
+ Field1Ty = CGT.ConvertType(EltTy);
+ Field1Off = CurOff;
+ assert(CurOff.isZero() && "Unexpected offset for first field");
+ Field2Ty = Field1Ty;
+ Field2Off = Field1Off + getContext().getTypeSizeInChars(EltTy);
+ return true;
+ }
+
+ if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(Ty)) {
+ uint64_t ArraySize = ATy->getSize().getZExtValue();
+ QualType EltTy = ATy->getElementType();
+ CharUnits EltSize = getContext().getTypeSizeInChars(EltTy);
+ for (uint64_t i = 0; i < ArraySize; ++i) {
+ bool Ret = detectFPCCEligibleStructHelper(EltTy, CurOff, Field1Ty,
+ Field1Off, Field2Ty, Field2Off);
+ if (!Ret)
+ return false;
+ CurOff += EltSize;
+ }
+ return true;
+ }
+
+ if (const auto *RTy = Ty->getAs<RecordType>()) {
+ // Structures with either a non-trivial destructor or a non-trivial
+ // copy constructor are not eligible for the FP calling convention.
+ if (getRecordArgABI(Ty, CGT.getCXXABI()))
+ return false;
+ if (isEmptyRecord(getContext(), Ty, true))
+ return true;
+ const RecordDecl *RD = RTy->getDecl();
+ // Unions aren't eligible unless they're empty (which is caught above).
+ if (RD->isUnion())
+ return false;
+ int ZeroWidthBitFieldCount = 0;
+ for (const FieldDecl *FD : RD->fields()) {
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
+ uint64_t FieldOffInBits = Layout.getFieldOffset(FD->getFieldIndex());
+ QualType QTy = FD->getType();
+ if (FD->isBitField()) {
+ unsigned BitWidth = FD->getBitWidthValue(getContext());
+ // Allow a bitfield with a type greater than XLen as long as the
+ // bitwidth is XLen or less.
+ if (getContext().getTypeSize(QTy) > XLen && BitWidth <= XLen)
+ QTy = getContext().getIntTypeForBitwidth(XLen, false);
+ if (BitWidth == 0) {
+ ZeroWidthBitFieldCount++;
+ continue;
+ }
+ }
+
+ bool Ret = detectFPCCEligibleStructHelper(
+ QTy, CurOff + getContext().toCharUnitsFromBits(FieldOffInBits),
+ Field1Ty, Field1Off, Field2Ty, Field2Off);
+ if (!Ret)
+ return false;
+
+ // As a quirk of the ABI, zero-width bitfields aren't ignored for fp+fp
+ // or int+fp structs, but are ignored for a struct with an fp field and
+ // any number of zero-width bitfields.
+ if (Field2Ty && ZeroWidthBitFieldCount > 0)
+ return false;
+ }
+ return Field1Ty != nullptr;
+ }
+
+ return false;
+}
+
+// Determine if a struct is eligible for passing according to the floating
+// point calling convention (i.e., when flattened it contains a single fp
+// value, fp+fp, or int+fp of appropriate size). If so, NeededArgFPRs and
+// NeededArgGPRs are incremented appropriately.
+bool RISCVABIInfo::detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty,
+ CharUnits &Field1Off,
+ llvm::Type *&Field2Ty,
+ CharUnits &Field2Off,
+ int &NeededArgGPRs,
+ int &NeededArgFPRs) const {
+ Field1Ty = nullptr;
+ Field2Ty = nullptr;
+ NeededArgGPRs = 0;
+ NeededArgFPRs = 0;
+ bool IsCandidate = detectFPCCEligibleStructHelper(
+ Ty, CharUnits::Zero(), Field1Ty, Field1Off, Field2Ty, Field2Off);
+ // Not really a candidate if we have a single int but no float.
+ if (Field1Ty && !Field2Ty && !Field1Ty->isFloatingPointTy())
+ return false;
+ if (!IsCandidate)
+ return false;
+ if (Field1Ty && Field1Ty->isFloatingPointTy())
+ NeededArgFPRs++;
+ else if (Field1Ty)
+ NeededArgGPRs++;
+ if (Field2Ty && Field2Ty->isFloatingPointTy())
+ NeededArgFPRs++;
+ else if (Field2Ty)
+ NeededArgGPRs++;
+ return IsCandidate;
+}
+
+// Call getCoerceAndExpand for the two-element flattened struct described by
+// Field1Ty, Field1Off, Field2Ty, Field2Off. This method will create an
+// appropriate coerceToType and unpaddedCoerceToType.
+ABIArgInfo RISCVABIInfo::coerceAndExpandFPCCEligibleStruct(
+ llvm::Type *Field1Ty, CharUnits Field1Off, llvm::Type *Field2Ty,
+ CharUnits Field2Off) const {
+ SmallVector<llvm::Type *, 3> CoerceElts;
+ SmallVector<llvm::Type *, 2> UnpaddedCoerceElts;
+ if (!Field1Off.isZero())
+ CoerceElts.push_back(llvm::ArrayType::get(
+ llvm::Type::getInt8Ty(getVMContext()), Field1Off.getQuantity()));
+
+ CoerceElts.push_back(Field1Ty);
+ UnpaddedCoerceElts.push_back(Field1Ty);
+
+ if (!Field2Ty) {
+ return ABIArgInfo::getCoerceAndExpand(
+ llvm::StructType::get(getVMContext(), CoerceElts, !Field1Off.isZero()),
+ UnpaddedCoerceElts[0]);
+ }
+
+ CharUnits Field2Align =
+ CharUnits::fromQuantity(getDataLayout().getABITypeAlignment(Field2Ty));
+ CharUnits Field1Size =
+ CharUnits::fromQuantity(getDataLayout().getTypeStoreSize(Field1Ty));
+ CharUnits Field2OffNoPadNoPack = Field1Size.alignTo(Field2Align);
+
+ CharUnits Padding = CharUnits::Zero();
+ if (Field2Off > Field2OffNoPadNoPack)
+ Padding = Field2Off - Field2OffNoPadNoPack;
+ else if (Field2Off != Field2Align && Field2Off > Field1Size)
+ Padding = Field2Off - Field1Size;
+
+ bool IsPacked = !Field2Off.isMultipleOf(Field2Align);
+
+ if (!Padding.isZero())
+ CoerceElts.push_back(llvm::ArrayType::get(
+ llvm::Type::getInt8Ty(getVMContext()), Padding.getQuantity()));
+
+ CoerceElts.push_back(Field2Ty);
+ UnpaddedCoerceElts.push_back(Field2Ty);
+
+ auto CoerceToType =
+ llvm::StructType::get(getVMContext(), CoerceElts, IsPacked);
+ auto UnpaddedCoerceToType =
+ llvm::StructType::get(getVMContext(), UnpaddedCoerceElts, IsPacked);
+
+ return ABIArgInfo::getCoerceAndExpand(CoerceToType, UnpaddedCoerceToType);
+}
+
ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
- int &ArgGPRsLeft) const {
+ int &ArgGPRsLeft,
+ int &ArgFPRsLeft) const {
assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow");
Ty = useFirstFieldIfTransparentUnion(Ty);
@@ -9257,6 +9522,42 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
return ABIArgInfo::getIgnore();
uint64_t Size = getContext().getTypeSize(Ty);
+
+ // Pass floating point values via FPRs if possible.
+ if (IsFixed && Ty->isFloatingType() && FLen >= Size && ArgFPRsLeft) {
+ ArgFPRsLeft--;
+ return ABIArgInfo::getDirect();
+ }
+
+ // Complex types for the hard float ABI must be passed direct rather than
+ // using CoerceAndExpand.
+ if (IsFixed && Ty->isComplexType() && FLen && ArgFPRsLeft >= 2) {
+ QualType EltTy = Ty->castAs<ComplexType>()->getElementType();
+ if (getContext().getTypeSize(EltTy) <= FLen) {
+ ArgFPRsLeft -= 2;
+ return ABIArgInfo::getDirect();
+ }
+ }
+
+ if (IsFixed && FLen && Ty->isStructureOrClassType()) {
+ llvm::Type *Field1Ty = nullptr;
+ llvm::Type *Field2Ty = nullptr;
+ CharUnits Field1Off = CharUnits::Zero();
+ CharUnits Field2Off = CharUnits::Zero();
+ int NeededArgGPRs;
+ int NeededArgFPRs;
+ bool IsCandidate =
+ detectFPCCEligibleStruct(Ty, Field1Ty, Field1Off, Field2Ty, Field2Off,
+ NeededArgGPRs, NeededArgFPRs);
+ if (IsCandidate && NeededArgGPRs <= ArgGPRsLeft &&
+ NeededArgFPRs <= ArgFPRsLeft) {
+ ArgGPRsLeft -= NeededArgGPRs;
+ ArgFPRsLeft -= NeededArgFPRs;
+ return coerceAndExpandFPCCEligibleStruct(Field1Ty, Field1Off, Field2Ty,
+ Field2Off);
+ }
+ }
+
uint64_t NeededAlign = getContext().getTypeAlign(Ty);
bool MustUseStack = false;
// Determine the number of GPRs needed to pass the current argument
@@ -9315,10 +9616,12 @@ ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy) const {
return ABIArgInfo::getIgnore();
int ArgGPRsLeft = 2;
+ int ArgFPRsLeft = FLen ? 2 : 0;
// The rules for return and argument types are the same, so defer to
// classifyArgumentType.
- return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft);
+ return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft,
+ ArgFPRsLeft);
}
Address RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
@@ -9353,8 +9656,9 @@ ABIArgInfo RISCVABIInfo::extendType(QualType Ty) const {
namespace {
class RISCVTargetCodeGenInfo : public TargetCodeGenInfo {
public:
- RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen)
- : TargetCodeGenInfo(new RISCVABIInfo(CGT, XLen)) {}
+ RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen,
+ unsigned FLen)
+ : TargetCodeGenInfo(new RISCVABIInfo(CGT, XLen, FLen)) {}
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &CGM) const override {
@@ -9460,7 +9764,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::ppc:
return SetCGInfo(
- new PPC32TargetCodeGenInfo(Types, CodeGenOpts.FloatABI == "soft"));
+ new PPC32TargetCodeGenInfo(Types, CodeGenOpts.FloatABI == "soft" ||
+ getTarget().hasFeature("spe")));
case llvm::Triple::ppc64:
if (Triple.isOSBinFormatELF()) {
PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv1;
@@ -9493,9 +9798,16 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
return SetCGInfo(new MSP430TargetCodeGenInfo(Types));
case llvm::Triple::riscv32:
- return SetCGInfo(new RISCVTargetCodeGenInfo(Types, 32));
- case llvm::Triple::riscv64:
- return SetCGInfo(new RISCVTargetCodeGenInfo(Types, 64));
+ case llvm::Triple::riscv64: {
+ StringRef ABIStr = getTarget().getABI();
+ unsigned XLen = getTarget().getPointerWidth(0);
+ unsigned ABIFLen = 0;
+ if (ABIStr.endswith("f"))
+ ABIFLen = 32;
+ else if (ABIStr.endswith("d"))
+ ABIFLen = 64;
+ return SetCGInfo(new RISCVTargetCodeGenInfo(Types, XLen, ABIFLen));
+ }
case llvm::Triple::systemz: {
bool HasVector = getTarget().getABI() == "vector";
@@ -9642,7 +9954,7 @@ llvm::Function *AMDGPUTargetCodeGenInfo::createEnqueuedBlockKernel(
Builder.SetInsertPoint(BB);
unsigned BlockAlign = CGF.CGM.getDataLayout().getPrefTypeAlignment(BlockTy);
auto *BlockPtr = Builder.CreateAlloca(BlockTy, nullptr);
- BlockPtr->setAlignment(BlockAlign);
+ BlockPtr->setAlignment(llvm::MaybeAlign(BlockAlign));
Builder.CreateAlignedStore(F->arg_begin(), BlockPtr, BlockAlign);
auto *Cast = Builder.CreatePointerCast(BlockPtr, InvokeFT->getParamType(0));
llvm::SmallVector<llvm::Value *, 2> Args;
diff --git a/lib/CrossTU/CrossTranslationUnit.cpp b/lib/CrossTU/CrossTranslationUnit.cpp
index 977fd4b8dd30..7391d7132daf 100644
--- a/lib/CrossTU/CrossTranslationUnit.cpp
+++ b/lib/CrossTU/CrossTranslationUnit.cpp
@@ -188,17 +188,17 @@ template <typename T> static bool hasBodyOrInit(const T *D) {
}
CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI)
- : CI(CI), Context(CI.getASTContext()),
- CTULoadThreshold(CI.getAnalyzerOpts()->CTUImportThreshold) {}
+ : Context(CI.getASTContext()), ASTStorage(CI) {}
CrossTranslationUnitContext::~CrossTranslationUnitContext() {}
-std::string CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) {
+llvm::Optional<std::string>
+CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) {
SmallString<128> DeclUSR;
bool Ret = index::generateUSRForDecl(ND, DeclUSR);
- (void)Ret;
- assert(!Ret && "Unable to generate USR");
- return DeclUSR.str();
+ if (Ret)
+ return {};
+ return std::string(DeclUSR.str());
}
/// Recursively visits the decls of a DeclContext, and returns one with the
@@ -218,7 +218,8 @@ CrossTranslationUnitContext::findDefInDeclContext(const DeclContext *DC,
const T *ResultDecl;
if (!ND || !hasBodyOrInit(ND, ResultDecl))
continue;
- if (getLookupName(ResultDecl) != LookupName)
+ llvm::Optional<std::string> ResultLookupName = getLookupName(ResultDecl);
+ if (!ResultLookupName || *ResultLookupName != LookupName)
continue;
return ResultDecl;
}
@@ -233,12 +234,12 @@ llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl(
assert(!hasBodyOrInit(D) &&
"D has a body or init in current translation unit!");
++NumGetCTUCalled;
- const std::string LookupName = getLookupName(D);
- if (LookupName.empty())
+ const llvm::Optional<std::string> LookupName = getLookupName(D);
+ if (!LookupName)
return llvm::make_error<IndexError>(
index_error_code::failed_to_generate_usr);
- llvm::Expected<ASTUnit *> ASTUnitOrError = loadExternalAST(
- LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
+ llvm::Expected<ASTUnit *> ASTUnitOrError =
+ loadExternalAST(*LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
if (!ASTUnitOrError)
return ASTUnitOrError.takeError();
ASTUnit *Unit = *ASTUnitOrError;
@@ -294,8 +295,8 @@ llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl(
}
TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
- if (const T *ResultDecl = findDefInDeclContext<T>(TU, LookupName))
- return importDefinition(ResultDecl);
+ if (const T *ResultDecl = findDefInDeclContext<T>(TU, *LookupName))
+ return importDefinition(ResultDecl, Unit);
return llvm::make_error<IndexError>(index_error_code::failed_import);
}
@@ -340,81 +341,168 @@ void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) {
}
}
-llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
- StringRef LookupName, StringRef CrossTUDir, StringRef IndexName,
- bool DisplayCTUProgress) {
- // FIXME: The current implementation only supports loading decls with
- // a lookup name from a single translation unit. If multiple
- // translation units contains decls with the same lookup name an
- // error will be returned.
-
- if (NumASTLoaded >= CTULoadThreshold) {
- ++NumASTLoadThresholdReached;
- return llvm::make_error<IndexError>(
- index_error_code::load_threshold_reached);
- }
+CrossTranslationUnitContext::ASTFileLoader::ASTFileLoader(
+ const CompilerInstance &CI)
+ : CI(CI) {}
+
+std::unique_ptr<ASTUnit>
+CrossTranslationUnitContext::ASTFileLoader::operator()(StringRef ASTFilePath) {
+ // Load AST from ast-dump.
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ TextDiagnosticPrinter *DiagClient =
+ new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
+
+ return ASTUnit::LoadFromASTFile(
+ ASTFilePath, CI.getPCHContainerOperations()->getRawReader(),
+ ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts());
+}
- ASTUnit *Unit = nullptr;
- auto NameUnitCacheEntry = NameASTUnitMap.find(LookupName);
- if (NameUnitCacheEntry == NameASTUnitMap.end()) {
- if (NameFileMap.empty()) {
- SmallString<256> IndexFile = CrossTUDir;
- if (llvm::sys::path::is_absolute(IndexName))
- IndexFile = IndexName;
- else
- llvm::sys::path::append(IndexFile, IndexName);
- llvm::Expected<llvm::StringMap<std::string>> IndexOrErr =
- parseCrossTUIndex(IndexFile, CrossTUDir);
- if (IndexOrErr)
- NameFileMap = *IndexOrErr;
- else
- return IndexOrErr.takeError();
+CrossTranslationUnitContext::ASTUnitStorage::ASTUnitStorage(
+ const CompilerInstance &CI)
+ : FileAccessor(CI), LoadGuard(const_cast<CompilerInstance &>(CI)
+ .getAnalyzerOpts()
+ ->CTUImportThreshold) {}
+
+llvm::Expected<ASTUnit *>
+CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFile(
+ StringRef FileName, bool DisplayCTUProgress) {
+ // Try the cache first.
+ auto ASTCacheEntry = FileASTUnitMap.find(FileName);
+ if (ASTCacheEntry == FileASTUnitMap.end()) {
+
+ // Do not load if the limit is reached.
+ if (!LoadGuard) {
+ ++NumASTLoadThresholdReached;
+ return llvm::make_error<IndexError>(
+ index_error_code::load_threshold_reached);
}
- auto It = NameFileMap.find(LookupName);
- if (It == NameFileMap.end()) {
+ // Load the ASTUnit from the pre-dumped AST file specified by ASTFileName.
+ std::unique_ptr<ASTUnit> LoadedUnit = FileAccessor(FileName);
+
+ // Need the raw pointer and the unique_ptr as well.
+ ASTUnit *Unit = LoadedUnit.get();
+
+ // Update the cache.
+ FileASTUnitMap[FileName] = std::move(LoadedUnit);
+
+ LoadGuard.indicateLoadSuccess();
+
+ if (DisplayCTUProgress)
+ llvm::errs() << "CTU loaded AST file: " << FileName << "\n";
+
+ return Unit;
+
+ } else {
+ // Found in the cache.
+ return ASTCacheEntry->second.get();
+ }
+}
+
+llvm::Expected<ASTUnit *>
+CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFunction(
+ StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName,
+ bool DisplayCTUProgress) {
+ // Try the cache first.
+ auto ASTCacheEntry = NameASTUnitMap.find(FunctionName);
+ if (ASTCacheEntry == NameASTUnitMap.end()) {
+ // Load the ASTUnit from the pre-dumped AST file specified by ASTFileName.
+
+ // Ensure that the Index is loaded, as we need to search in it.
+ if (llvm::Error IndexLoadError =
+ ensureCTUIndexLoaded(CrossTUDir, IndexName))
+ return std::move(IndexLoadError);
+
+ // Check if there is and entry in the index for the function.
+ if (!NameFileMap.count(FunctionName)) {
++NumNotInOtherTU;
return llvm::make_error<IndexError>(index_error_code::missing_definition);
}
- StringRef ASTFileName = It->second;
- auto ASTCacheEntry = FileASTUnitMap.find(ASTFileName);
- if (ASTCacheEntry == FileASTUnitMap.end()) {
- IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
- TextDiagnosticPrinter *DiagClient =
- new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
- IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
- new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
-
- std::unique_ptr<ASTUnit> LoadedUnit(ASTUnit::LoadFromASTFile(
- ASTFileName, CI.getPCHContainerOperations()->getRawReader(),
- ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts()));
- Unit = LoadedUnit.get();
- FileASTUnitMap[ASTFileName] = std::move(LoadedUnit);
- ++NumASTLoaded;
- if (DisplayCTUProgress) {
- llvm::errs() << "CTU loaded AST file: "
- << ASTFileName << "\n";
- }
+
+ // Search in the index for the filename where the definition of FuncitonName
+ // resides.
+ if (llvm::Expected<ASTUnit *> FoundForFile =
+ getASTUnitForFile(NameFileMap[FunctionName], DisplayCTUProgress)) {
+
+ // Update the cache.
+ NameASTUnitMap[FunctionName] = *FoundForFile;
+ return *FoundForFile;
+
} else {
- Unit = ASTCacheEntry->second.get();
+ return FoundForFile.takeError();
}
- NameASTUnitMap[LookupName] = Unit;
} else {
- Unit = NameUnitCacheEntry->second;
+ // Found in the cache.
+ return ASTCacheEntry->second;
}
+}
+
+llvm::Expected<std::string>
+CrossTranslationUnitContext::ASTUnitStorage::getFileForFunction(
+ StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName) {
+ if (llvm::Error IndexLoadError = ensureCTUIndexLoaded(CrossTUDir, IndexName))
+ return std::move(IndexLoadError);
+ return NameFileMap[FunctionName];
+}
+
+llvm::Error CrossTranslationUnitContext::ASTUnitStorage::ensureCTUIndexLoaded(
+ StringRef CrossTUDir, StringRef IndexName) {
+ // Dont initialize if the map is filled.
+ if (!NameFileMap.empty())
+ return llvm::Error::success();
+
+ // Get the absolute path to the index file.
+ SmallString<256> IndexFile = CrossTUDir;
+ if (llvm::sys::path::is_absolute(IndexName))
+ IndexFile = IndexName;
+ else
+ llvm::sys::path::append(IndexFile, IndexName);
+
+ if (auto IndexMapping = parseCrossTUIndex(IndexFile, CrossTUDir)) {
+ // Initialize member map.
+ NameFileMap = *IndexMapping;
+ return llvm::Error::success();
+ } else {
+ // Error while parsing CrossTU index file.
+ return IndexMapping.takeError();
+ };
+}
+
+llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
+ StringRef LookupName, StringRef CrossTUDir, StringRef IndexName,
+ bool DisplayCTUProgress) {
+ // FIXME: The current implementation only supports loading decls with
+ // a lookup name from a single translation unit. If multiple
+ // translation units contains decls with the same lookup name an
+ // error will be returned.
+
+ // Try to get the value from the heavily cached storage.
+ llvm::Expected<ASTUnit *> Unit = ASTStorage.getASTUnitForFunction(
+ LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
+
if (!Unit)
+ return Unit.takeError();
+
+ // Check whether the backing pointer of the Expected is a nullptr.
+ if (!*Unit)
return llvm::make_error<IndexError>(
index_error_code::failed_to_get_external_ast);
+
return Unit;
}
template <typename T>
llvm::Expected<const T *>
-CrossTranslationUnitContext::importDefinitionImpl(const T *D) {
+CrossTranslationUnitContext::importDefinitionImpl(const T *D, ASTUnit *Unit) {
assert(hasBodyOrInit(D) && "Decls to be imported should have body or init.");
- ASTImporter &Importer = getOrCreateASTImporter(D->getASTContext());
+ assert(&D->getASTContext() == &Unit->getASTContext() &&
+ "ASTContext of Decl and the unit should match.");
+ ASTImporter &Importer = getOrCreateASTImporter(Unit);
+
auto ToDeclOrError = Importer.Import(D);
if (!ToDeclOrError) {
handleAllErrors(ToDeclOrError.takeError(),
@@ -441,13 +529,15 @@ CrossTranslationUnitContext::importDefinitionImpl(const T *D) {
}
llvm::Expected<const FunctionDecl *>
-CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD) {
- return importDefinitionImpl(FD);
+CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD,
+ ASTUnit *Unit) {
+ return importDefinitionImpl(FD, Unit);
}
llvm::Expected<const VarDecl *>
-CrossTranslationUnitContext::importDefinition(const VarDecl *VD) {
- return importDefinitionImpl(VD);
+CrossTranslationUnitContext::importDefinition(const VarDecl *VD,
+ ASTUnit *Unit) {
+ return importDefinitionImpl(VD, Unit);
}
void CrossTranslationUnitContext::lazyInitImporterSharedSt(
@@ -457,7 +547,9 @@ void CrossTranslationUnitContext::lazyInitImporterSharedSt(
}
ASTImporter &
-CrossTranslationUnitContext::getOrCreateASTImporter(ASTContext &From) {
+CrossTranslationUnitContext::getOrCreateASTImporter(ASTUnit *Unit) {
+ ASTContext &From = Unit->getASTContext();
+
auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl());
if (I != ASTUnitImporterMap.end())
return *I->second;
@@ -465,9 +557,32 @@ CrossTranslationUnitContext::getOrCreateASTImporter(ASTContext &From) {
ASTImporter *NewImporter = new ASTImporter(
Context, Context.getSourceManager().getFileManager(), From,
From.getSourceManager().getFileManager(), false, ImporterSharedSt);
+ NewImporter->setFileIDImportHandler([this, Unit](FileID ToID, FileID FromID) {
+ assert(ImportedFileIDs.find(ToID) == ImportedFileIDs.end() &&
+ "FileID already imported, should not happen.");
+ ImportedFileIDs[ToID] = std::make_pair(FromID, Unit);
+ });
ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter);
return *NewImporter;
}
+llvm::Optional<std::pair<SourceLocation, ASTUnit *>>
+CrossTranslationUnitContext::getImportedFromSourceLocation(
+ const clang::SourceLocation &ToLoc) const {
+ const SourceManager &SM = Context.getSourceManager();
+ auto DecToLoc = SM.getDecomposedLoc(ToLoc);
+
+ auto I = ImportedFileIDs.find(DecToLoc.first);
+ if (I == ImportedFileIDs.end())
+ return {};
+
+ FileID FromID = I->second.first;
+ clang::ASTUnit *Unit = I->second.second;
+ SourceLocation FromLoc =
+ Unit->getSourceManager().getComposedLoc(FromID, DecToLoc.second);
+
+ return std::make_pair(FromLoc, Unit);
+}
+
} // namespace cross_tu
} // namespace clang
diff --git a/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp b/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp
index e330ff06f504..200e540624a6 100644
--- a/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp
+++ b/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp
@@ -11,9 +11,11 @@
using namespace llvm;
using namespace clang;
-std::unique_ptr<DirectoryWatcher> clang::DirectoryWatcher::create(
+llvm::Expected<std::unique_ptr<DirectoryWatcher>> clang::DirectoryWatcher::create(
StringRef Path,
std::function<void(llvm::ArrayRef<DirectoryWatcher::Event>, bool)> Receiver,
bool WaitForInitialSync) {
- return nullptr;
+ return llvm::make_error<llvm::StringError>(
+ "DirectoryWatcher is not implemented for this platform!",
+ llvm::inconvertibleErrorCode());
} \ No newline at end of file
diff --git a/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp b/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
index 6d7d69da4db5..176d6d6abf33 100644
--- a/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
+++ b/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
@@ -13,7 +13,7 @@
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Errno.h"
-#include "llvm/Support/Mutex.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/Path.h"
#include <atomic>
#include <condition_variable>
@@ -24,7 +24,6 @@
#include <vector>
#include <fcntl.h>
-#include <linux/version.h>
#include <sys/epoll.h>
#include <sys/inotify.h>
#include <unistd.h>
@@ -184,9 +183,10 @@ void DirectoryWatcherLinux::InotifyPollingLoop() {
// the inotify file descriptor should have the same alignment as
// struct inotify_event.
- auto ManagedBuffer =
- llvm::make_unique<llvm::AlignedCharArray<alignof(struct inotify_event),
- EventBufferLength>>();
+ struct Buffer {
+ alignas(struct inotify_event) char buffer[EventBufferLength];
+ };
+ auto ManagedBuffer = std::make_unique<Buffer>();
char *const Buf = ManagedBuffer->buffer;
const int EpollFD = epoll_create1(EPOLL_CLOEXEC);
@@ -320,34 +320,41 @@ DirectoryWatcherLinux::DirectoryWatcherLinux(
} // namespace
-std::unique_ptr<DirectoryWatcher> clang::DirectoryWatcher::create(
+llvm::Expected<std::unique_ptr<DirectoryWatcher>> clang::DirectoryWatcher::create(
StringRef Path,
std::function<void(llvm::ArrayRef<DirectoryWatcher::Event>, bool)> Receiver,
bool WaitForInitialSync) {
if (Path.empty())
- return nullptr;
+ llvm::report_fatal_error(
+ "DirectoryWatcher::create can not accept an empty Path.");
const int InotifyFD = inotify_init1(IN_CLOEXEC);
if (InotifyFD == -1)
- return nullptr;
+ return llvm::make_error<llvm::StringError>(
+ std::string("inotify_init1() error: ") + strerror(errno),
+ llvm::inconvertibleErrorCode());
const int InotifyWD = inotify_add_watch(
InotifyFD, Path.str().c_str(),
IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY |
IN_MOVED_FROM | IN_MOVE_SELF | IN_MOVED_TO | IN_ONLYDIR | IN_IGNORED
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
+#ifdef IN_EXCL_UNLINK
| IN_EXCL_UNLINK
#endif
);
if (InotifyWD == -1)
- return nullptr;
+ return llvm::make_error<llvm::StringError>(
+ std::string("inotify_add_watch() error: ") + strerror(errno),
+ llvm::inconvertibleErrorCode());
auto InotifyPollingStopper = SemaphorePipe::create();
if (!InotifyPollingStopper)
- return nullptr;
+ return llvm::make_error<llvm::StringError>(
+ std::string("SemaphorePipe::create() error: ") + strerror(errno),
+ llvm::inconvertibleErrorCode());
- return llvm::make_unique<DirectoryWatcherLinux>(
+ return std::make_unique<DirectoryWatcherLinux>(
Path, Receiver, WaitForInitialSync, InotifyFD, InotifyWD,
std::move(*InotifyPollingStopper));
-} \ No newline at end of file
+}
diff --git a/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp b/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp
index 3df79ac48a4a..7a60369a4da0 100644
--- a/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp
+++ b/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp
@@ -11,20 +11,35 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/Path.h"
#include <CoreServices/CoreServices.h>
using namespace llvm;
using namespace clang;
-static FSEventStreamRef createFSEventStream(
- StringRef Path,
- std::function<void(llvm::ArrayRef<DirectoryWatcher::Event>, bool)>,
- dispatch_queue_t);
static void stopFSEventStream(FSEventStreamRef);
namespace {
+/// This implementation is based on FSEvents API which implementation is
+/// aggressively coallescing events. This can manifest as duplicate events.
+///
+/// For example this scenario has been observed:
+///
+/// create foo/bar
+/// sleep 5 s
+/// create DirectoryWatcherMac for dir foo
+/// receive notification: bar EventKind::Modified
+/// sleep 5 s
+/// modify foo/bar
+/// receive notification: bar EventKind::Modified
+/// receive notification: bar EventKind::Modified
+/// sleep 5 s
+/// delete foo/bar
+/// receive notification: bar EventKind::Modified
+/// receive notification: bar EventKind::Modified
+/// receive notification: bar EventKind::Removed
class DirectoryWatcherMac : public clang::DirectoryWatcher {
public:
DirectoryWatcherMac(
@@ -187,7 +202,7 @@ void stopFSEventStream(FSEventStreamRef EventStream) {
FSEventStreamRelease(EventStream);
}
-std::unique_ptr<DirectoryWatcher> clang::DirectoryWatcher::create(
+llvm::Expected<std::unique_ptr<DirectoryWatcher>> clang::DirectoryWatcher::create(
StringRef Path,
std::function<void(llvm::ArrayRef<DirectoryWatcher::Event>, bool)> Receiver,
bool WaitForInitialSync) {
@@ -195,15 +210,14 @@ std::unique_ptr<DirectoryWatcher> clang::DirectoryWatcher::create(
dispatch_queue_create("DirectoryWatcher", DISPATCH_QUEUE_SERIAL);
if (Path.empty())
- return nullptr;
+ llvm::report_fatal_error(
+ "DirectoryWatcher::create can not accept an empty Path.");
auto EventStream = createFSEventStream(Path, Receiver, Queue);
- if (!EventStream) {
- return nullptr;
- }
+ assert(EventStream && "EventStream expected to be non-null");
std::unique_ptr<DirectoryWatcher> Result =
- llvm::make_unique<DirectoryWatcherMac>(EventStream, Receiver, Path);
+ std::make_unique<DirectoryWatcherMac>(EventStream, Receiver, Path);
// We need to copy the data so the lifetime is ok after a const copy is made
// for the block.
diff --git a/lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp b/lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp
new file mode 100644
index 000000000000..25cbcf536388
--- /dev/null
+++ b/lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp
@@ -0,0 +1,50 @@
+//===- DirectoryWatcher-windows.cpp - Windows-platform directory watching -===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// TODO: This is not yet an implementation, but it will make it so Windows
+// builds don't fail.
+
+#include "DirectoryScanner.h"
+#include "clang/DirectoryWatcher/DirectoryWatcher.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/Support/AlignOf.h"
+#include "llvm/Support/Errno.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/Path.h"
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace {
+
+using namespace llvm;
+using namespace clang;
+
+class DirectoryWatcherWindows : public clang::DirectoryWatcher {
+public:
+ ~DirectoryWatcherWindows() override { }
+ void InitialScan() { }
+ void EventReceivingLoop() { }
+ void StopWork() { }
+};
+} // namespace
+
+llvm::Expected<std::unique_ptr<DirectoryWatcher>>
+clang::DirectoryWatcher::create(
+ StringRef Path,
+ std::function<void(llvm::ArrayRef<DirectoryWatcher::Event>, bool)> Receiver,
+ bool WaitForInitialSync) {
+ return llvm::Expected<std::unique_ptr<DirectoryWatcher>>(
+ llvm::errorCodeToError(std::make_error_code(std::errc::not_supported)));
+}
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp
index 47b03f6643b8..0eb4c7257e7a 100644
--- a/lib/Driver/Action.cpp
+++ b/lib/Driver/Action.cpp
@@ -31,6 +31,7 @@ const char *Action::getClassName(ActionClass AC) {
case CompileJobClass: return "compiler";
case BackendJobClass: return "backend";
case AssembleJobClass: return "assembler";
+ case IfsMergeJobClass: return "interface-stub-merger";
case LinkJobClass: return "linker";
case LipoJobClass: return "lipo";
case DsymutilJobClass: return "dsymutil";
@@ -40,6 +41,8 @@ const char *Action::getClassName(ActionClass AC) {
return "clang-offload-bundler";
case OffloadUnbundlingJobClass:
return "clang-offload-unbundler";
+ case OffloadWrapperJobClass:
+ return "clang-offload-wrapper";
}
llvm_unreachable("invalid class");
@@ -357,6 +360,11 @@ void AssembleJobAction::anchor() {}
AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
: JobAction(AssembleJobClass, Input, OutputType) {}
+void IfsMergeJobAction::anchor() {}
+
+IfsMergeJobAction::IfsMergeJobAction(ActionList &Inputs, types::ID Type)
+ : JobAction(IfsMergeJobClass, Inputs, Type) {}
+
void LinkJobAction::anchor() {}
LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type)
@@ -401,3 +409,9 @@ void OffloadUnbundlingJobAction::anchor() {}
OffloadUnbundlingJobAction::OffloadUnbundlingJobAction(Action *Input)
: JobAction(OffloadUnbundlingJobClass, Input, Input->getType()) {}
+
+void OffloadWrapperJobAction::anchor() {}
+
+OffloadWrapperJobAction::OffloadWrapperJobAction(ActionList &Inputs,
+ types::ID Type)
+ : JobAction(OffloadWrapperJobClass, Inputs, Type) {}
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index 5f3026e6ce50..ba188f5c4083 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -161,7 +161,7 @@ int Compilation::ExecuteCommand(const Command &C,
std::error_code EC;
OwnedStream.reset(new llvm::raw_fd_ostream(
getDriver().CCPrintOptionsFilename, EC,
- llvm::sys::fs::F_Append | llvm::sys::fs::F_Text));
+ llvm::sys::fs::OF_Append | llvm::sys::fs::OF_Text));
if (EC) {
getDriver().Diag(diag::err_drv_cc_print_options_failure)
<< EC.message();
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 396ddf4dd816..f6016b43b692 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -120,20 +120,20 @@ std::string Driver::GetResourcesPath(StringRef BinaryPath,
Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
DiagnosticsEngine &Diags,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)
- : Opts(createDriverOptTable()), Diags(Diags), VFS(std::move(VFS)),
- Mode(GCCMode), SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone),
- LTOMode(LTOK_None), ClangExecutable(ClangExecutable),
- SysRoot(DEFAULT_SYSROOT), DriverTitle("clang LLVM compiler"),
- CCPrintOptionsFilename(nullptr), CCPrintHeadersFilename(nullptr),
- CCLogDiagnosticsFilename(nullptr), CCCPrintBindings(false),
- CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false),
- CCGenDiagnostics(false), TargetTriple(TargetTriple),
- CCCGenericGCCName(""), Saver(Alloc), CheckInputsExist(true),
- GenReproducer(false), SuppressMissingInputWarning(false) {
+ : Diags(Diags), VFS(std::move(VFS)), Mode(GCCMode),
+ SaveTemps(SaveTempsNone), BitcodeEmbed(EmbedNone), LTOMode(LTOK_None),
+ ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
+ DriverTitle("clang LLVM compiler"), CCPrintOptionsFilename(nullptr),
+ CCPrintHeadersFilename(nullptr), CCLogDiagnosticsFilename(nullptr),
+ CCCPrintBindings(false), CCPrintOptions(false), CCPrintHeaders(false),
+ CCLogDiagnostics(false), CCGenDiagnostics(false),
+ TargetTriple(TargetTriple), CCCGenericGCCName(""), Saver(Alloc),
+ CheckInputsExist(true), GenReproducer(false),
+ SuppressMissingInputWarning(false) {
// Provide a sane fallback if no VFS is specified.
if (!this->VFS)
- this->VFS = llvm::vfs::createPhysicalFileSystem().release();
+ this->VFS = llvm::vfs::getRealFileSystem();
Name = llvm::sys::path::filename(ClangExecutable);
Dir = llvm::sys::path::parent_path(ClangExecutable);
@@ -274,11 +274,11 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL,
(PhaseArg = DAL.getLastArg(options::OPT__SLASH_P))) {
FinalPhase = phases::Preprocess;
- // --precompile only runs up to precompilation.
+ // --precompile only runs up to precompilation.
} else if ((PhaseArg = DAL.getLastArg(options::OPT__precompile))) {
FinalPhase = phases::Precompile;
- // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
+ // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
} else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) ||
(PhaseArg = DAL.getLastArg(options::OPT_print_supported_cpus)) ||
(PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) ||
@@ -286,21 +286,23 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL,
(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_emit_iterface_stubs)) ||
- (PhaseArg = DAL.getLastArg(options::OPT__analyze,
- options::OPT__analyze_auto)) ||
+ (PhaseArg = DAL.getLastArg(options::OPT__analyze)) ||
(PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) {
FinalPhase = phases::Compile;
- // -S only runs up to the backend.
+ // clang interface stubs
+ } else if ((PhaseArg = DAL.getLastArg(options::OPT_emit_interface_stubs))) {
+ FinalPhase = phases::IfsMerge;
+
+ // -S only runs up to the backend.
} else if ((PhaseArg = DAL.getLastArg(options::OPT_S))) {
FinalPhase = phases::Backend;
- // -c compilation only runs up to the assembler.
+ // -c compilation only runs up to the assembler.
} else if ((PhaseArg = DAL.getLastArg(options::OPT_c))) {
FinalPhase = phases::Assemble;
- // Otherwise do everything.
+ // Otherwise do everything.
} else
FinalPhase = phases::Link;
@@ -310,7 +312,7 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL,
return FinalPhase;
}
-static Arg *MakeInputArg(DerivedArgList &Args, OptTable &Opts,
+static Arg *MakeInputArg(DerivedArgList &Args, const OptTable &Opts,
StringRef Value, bool Claim = true) {
Arg *A = new Arg(Opts.getOption(options::OPT_INPUT), Value,
Args.getBaseArgs().MakeIndex(Value), Value.data());
@@ -321,6 +323,7 @@ static Arg *MakeInputArg(DerivedArgList &Args, OptTable &Opts,
}
DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
+ const llvm::opt::OptTable &Opts = getOpts();
DerivedArgList *DAL = new DerivedArgList(Args);
bool HasNostdlib = Args.hasArg(options::OPT_nostdlib);
@@ -337,12 +340,12 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
A->getOption().matches(options::OPT_Xlinker)) &&
A->containsValue("--no-demangle")) {
// Add the rewritten no-demangle argument.
- DAL->AddFlagArg(A, Opts->getOption(options::OPT_Z_Xlinker__no_demangle));
+ DAL->AddFlagArg(A, Opts.getOption(options::OPT_Z_Xlinker__no_demangle));
// Add the remaining values as Xlinker arguments.
for (StringRef Val : A->getValues())
if (Val != "--no-demangle")
- DAL->AddSeparateArg(A, Opts->getOption(options::OPT_Xlinker), Val);
+ DAL->AddSeparateArg(A, Opts.getOption(options::OPT_Xlinker), Val);
continue;
}
@@ -355,12 +358,11 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
A->getValue(0) == StringRef("-MMD"))) {
// Rewrite to -MD/-MMD along with -MF.
if (A->getValue(0) == StringRef("-MD"))
- DAL->AddFlagArg(A, Opts->getOption(options::OPT_MD));
+ DAL->AddFlagArg(A, Opts.getOption(options::OPT_MD));
else
- DAL->AddFlagArg(A, Opts->getOption(options::OPT_MMD));
+ DAL->AddFlagArg(A, Opts.getOption(options::OPT_MMD));
if (A->getNumValues() == 2)
- DAL->AddSeparateArg(A, Opts->getOption(options::OPT_MF),
- A->getValue(1));
+ DAL->AddSeparateArg(A, Opts.getOption(options::OPT_MF), A->getValue(1));
continue;
}
@@ -371,13 +373,13 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
// Rewrite unless -nostdlib is present.
if (!HasNostdlib && !HasNodefaultlib && !HasNostdlibxx &&
Value == "stdc++") {
- DAL->AddFlagArg(A, Opts->getOption(options::OPT_Z_reserved_lib_stdcxx));
+ DAL->AddFlagArg(A, Opts.getOption(options::OPT_Z_reserved_lib_stdcxx));
continue;
}
// Rewrite unconditionally.
if (Value == "cc_kext") {
- DAL->AddFlagArg(A, Opts->getOption(options::OPT_Z_reserved_lib_cckext));
+ DAL->AddFlagArg(A, Opts.getOption(options::OPT_Z_reserved_lib_cckext));
continue;
}
}
@@ -386,7 +388,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
if (A->getOption().matches(options::OPT__DASH_DASH)) {
A->claim();
for (StringRef Val : A->getValues())
- DAL->append(MakeInputArg(*DAL, *Opts, Val, false));
+ DAL->append(MakeInputArg(*DAL, Opts, Val, false));
continue;
}
@@ -395,14 +397,14 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const {
// Enforce -static if -miamcu is present.
if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false))
- DAL->AddFlagArg(0, Opts->getOption(options::OPT_static));
+ DAL->AddFlagArg(0, Opts.getOption(options::OPT_static));
// Add a default value of -mlinker-version=, if one was given and the user
// didn't specify one.
#if defined(HOST_LINK_VERSION)
if (!Args.hasArg(options::OPT_mlinker_version_EQ) &&
strlen(HOST_LINK_VERSION) > 0) {
- DAL->AddJoinedArg(0, Opts->getOption(options::OPT_mlinker_version_EQ),
+ DAL->AddJoinedArg(0, Opts.getOption(options::OPT_mlinker_version_EQ),
HOST_LINK_VERSION);
DAL->getLastArg(options::OPT_mlinker_version_EQ)->claim();
}
@@ -626,7 +628,7 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
// because the device toolchain we create depends on both.
auto &CudaTC = ToolChains[CudaTriple.str() + "/" + HostTriple.str()];
if (!CudaTC) {
- CudaTC = llvm::make_unique<toolchains::CudaToolChain>(
+ CudaTC = std::make_unique<toolchains::CudaToolChain>(
*this, CudaTriple, *HostTC, C.getInputArgs(), OFK);
}
C.addOffloadDeviceToolChain(CudaTC.get(), OFK);
@@ -641,7 +643,7 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
// because the device toolchain we create depends on both.
auto &HIPTC = ToolChains[HIPTriple.str() + "/" + HostTriple.str()];
if (!HIPTC) {
- HIPTC = llvm::make_unique<toolchains::HIPToolChain>(
+ HIPTC = std::make_unique<toolchains::HIPToolChain>(
*this, HIPTriple, *HostTC, C.getInputArgs());
}
C.addOffloadDeviceToolChain(HIPTC.get(), OFK);
@@ -699,7 +701,7 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
auto &CudaTC =
ToolChains[TT.str() + "/" + HostTC->getTriple().normalize()];
if (!CudaTC)
- CudaTC = llvm::make_unique<toolchains::CudaToolChain>(
+ CudaTC = std::make_unique<toolchains::CudaToolChain>(
*this, TT, *HostTC, C.getInputArgs(), Action::OFK_OpenMP);
TC = CudaTC.get();
} else
@@ -760,7 +762,7 @@ bool Driver::readConfigFile(StringRef FileName) {
llvm::sys::path::native(CfgFileName);
ConfigFile = CfgFileName.str();
bool ContainErrors;
- CfgOptions = llvm::make_unique<InputArgList>(
+ CfgOptions = std::make_unique<InputArgList>(
ParseArgStrings(NewCfgArgs, IsCLMode(), ContainErrors));
if (ContainErrors) {
CfgOptions.reset();
@@ -954,7 +956,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// Arguments specified in command line.
bool ContainsError;
- CLOptions = llvm::make_unique<InputArgList>(
+ CLOptions = std::make_unique<InputArgList>(
ParseArgStrings(ArgList.slice(1), IsCLMode(), ContainsError));
// Try parsing configuration file.
@@ -1000,7 +1002,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
if (!CLModePassThroughArgList.empty()) {
// Parse any pass through args using default clang processing rather
// than clang-cl processing.
- auto CLModePassThroughOptions = llvm::make_unique<InputArgList>(
+ auto CLModePassThroughOptions = std::make_unique<InputArgList>(
ParseArgStrings(CLModePassThroughArgList, false, ContainsError));
if (!ContainsError)
@@ -1093,7 +1095,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
}
std::unique_ptr<llvm::opt::InputArgList> UArgs =
- llvm::make_unique<InputArgList>(std::move(Args));
+ std::make_unique<InputArgList>(std::move(Args));
// Perform the default argument translations.
DerivedArgList *TranslatedArgs = TranslateInputArgs(*UArgs);
@@ -1592,16 +1594,17 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const {
if (llvm::is_contained(Flags, "-Xclang") || llvm::is_contained(Flags, "-cc1"))
DisableFlags &= ~options::NoDriverOption;
+ const llvm::opt::OptTable &Opts = getOpts();
StringRef Cur;
Cur = Flags.at(Flags.size() - 1);
StringRef Prev;
if (Flags.size() >= 2) {
Prev = Flags.at(Flags.size() - 2);
- SuggestedCompletions = Opts->suggestValueCompletions(Prev, Cur);
+ SuggestedCompletions = Opts.suggestValueCompletions(Prev, Cur);
}
if (SuggestedCompletions.empty())
- SuggestedCompletions = Opts->suggestValueCompletions(Cur, "");
+ SuggestedCompletions = Opts.suggestValueCompletions(Cur, "");
// If Flags were empty, it means the user typed `clang [tab]` where we should
// list all possible flags. If there was no value completion and the user
@@ -1619,7 +1622,7 @@ void Driver::HandleAutocompletions(StringRef PassedFlags) const {
// If the flag is in the form of "--autocomplete=-foo",
// we were requested to print out all option names that start with "-foo".
// For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only".
- SuggestedCompletions = Opts->findByPrefix(Cur, DisableFlags);
+ SuggestedCompletions = Opts.findByPrefix(Cur, DisableFlags);
// We have to query the -W flags manually as they're not in the OptTable.
// TODO: Find a good way to add them to OptTable instead and them remove
@@ -1799,23 +1802,36 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
return true;
}
+enum {
+ TopLevelAction = 0,
+ HeadSibAction = 1,
+ OtherSibAction = 2,
+};
+
// Display an action graph human-readably. Action A is the "sink" node
// and latest-occuring action. Traversal is in pre-order, visiting the
// inputs to each action before printing the action itself.
static unsigned PrintActions1(const Compilation &C, Action *A,
- std::map<Action *, unsigned> &Ids) {
+ std::map<Action *, unsigned> &Ids,
+ Twine Indent = {}, int Kind = TopLevelAction) {
if (Ids.count(A)) // A was already visited.
return Ids[A];
std::string str;
llvm::raw_string_ostream os(str);
+ auto getSibIndent = [](int K) -> Twine {
+ return (K == HeadSibAction) ? " " : (K == OtherSibAction) ? "| " : "";
+ };
+
+ Twine SibIndent = Indent + getSibIndent(Kind);
+ int SibKind = HeadSibAction;
os << Action::getClassName(A->getKind()) << ", ";
if (InputAction *IA = dyn_cast<InputAction>(A)) {
os << "\"" << IA->getInputArg().getValue() << "\"";
} else if (BindArchAction *BIA = dyn_cast<BindArchAction>(A)) {
os << '"' << BIA->getArchName() << '"' << ", {"
- << PrintActions1(C, *BIA->input_begin(), Ids) << "}";
+ << PrintActions1(C, *BIA->input_begin(), Ids, SibIndent, SibKind) << "}";
} else if (OffloadAction *OA = dyn_cast<OffloadAction>(A)) {
bool IsFirst = true;
OA->doOnEachDependence(
@@ -1838,8 +1854,9 @@ static unsigned PrintActions1(const Compilation &C, Action *A,
os << ":" << BoundArch;
os << ")";
os << '"';
- os << " {" << PrintActions1(C, A, Ids) << "}";
+ os << " {" << PrintActions1(C, A, Ids, SibIndent, SibKind) << "}";
IsFirst = false;
+ SibKind = OtherSibAction;
});
} else {
const ActionList *AL = &A->getInputs();
@@ -1847,8 +1864,9 @@ static unsigned PrintActions1(const Compilation &C, Action *A,
if (AL->size()) {
const char *Prefix = "{";
for (Action *PreRequisite : *AL) {
- os << Prefix << PrintActions1(C, PreRequisite, Ids);
+ os << Prefix << PrintActions1(C, PreRequisite, Ids, SibIndent, SibKind);
Prefix = ", ";
+ SibKind = OtherSibAction;
}
os << "}";
} else
@@ -1869,9 +1887,13 @@ static unsigned PrintActions1(const Compilation &C, Action *A,
}
}
+ auto getSelfIndent = [](int K) -> Twine {
+ return (K == HeadSibAction) ? "+- " : (K == OtherSibAction) ? "|- " : "";
+ };
+
unsigned Id = Ids.size();
Ids[A] = Id;
- llvm::errs() << Id << ": " << os.str() << ", "
+ llvm::errs() << Indent + getSelfIndent(Kind) << Id << ": " << os.str() << ", "
<< types::getTypeName(A->getType()) << offload_os.str() << "\n";
return Id;
@@ -2037,6 +2059,7 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value,
// Construct a the list of inputs and their types.
void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
InputList &Inputs) const {
+ const llvm::opt::OptTable &Opts = getOpts();
// Track the current user specified (-x) input. We also explicitly track the
// argument used to set the type; we only want to claim the type when we
// actually use it, so we warn about unused -x arguments.
@@ -2160,7 +2183,7 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
StringRef Value = A->getValue();
if (DiagnoseInputExistence(Args, Value, types::TY_C,
/*TypoCorrect=*/false)) {
- Arg *InputArg = MakeInputArg(Args, *Opts, A->getValue());
+ Arg *InputArg = MakeInputArg(Args, Opts, A->getValue());
Inputs.push_back(std::make_pair(types::TY_C, InputArg));
}
A->claim();
@@ -2168,7 +2191,7 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
StringRef Value = A->getValue();
if (DiagnoseInputExistence(Args, Value, types::TY_CXX,
/*TypoCorrect=*/false)) {
- Arg *InputArg = MakeInputArg(Args, *Opts, A->getValue());
+ Arg *InputArg = MakeInputArg(Args, Opts, A->getValue());
Inputs.push_back(std::make_pair(types::TY_CXX, InputArg));
}
A->claim();
@@ -2202,7 +2225,7 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
if (CCCIsCPP() && Inputs.empty()) {
// If called as standalone preprocessor, stdin is processed
// if no other input is present.
- Arg *A = MakeInputArg(Args, *Opts, "-");
+ Arg *A = MakeInputArg(Args, Opts, "-");
Inputs.push_back(std::make_pair(types::TY_C, A));
}
}
@@ -2223,7 +2246,7 @@ class OffloadingActionBuilder final {
/// Builder interface. It doesn't build anything or keep any state.
class DeviceActionBuilder {
public:
- typedef llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PhasesTy;
+ typedef const llvm::SmallVectorImpl<phases::ID> PhasesTy;
enum ActionBuilderReturnCode {
// The builder acted successfully on the current action.
@@ -2276,12 +2299,13 @@ class OffloadingActionBuilder final {
return ABRT_Inactive;
}
- /// Append top level actions generated by the builder. Return true if errors
- /// were found.
+ /// Append top level actions generated by the builder.
virtual void appendTopLevelActions(ActionList &AL) {}
- /// Append linker actions generated by the builder. Return true if errors
- /// were found.
+ /// Append linker actions generated by the builder.
+ virtual void appendLinkActions(ActionList &AL) {}
+
+ /// Append linker actions generated by the builder.
virtual void appendLinkDependences(OffloadAction::DeviceDependences &DA) {}
/// Initialize the builder. Return true if any initialization errors are
@@ -2309,6 +2333,8 @@ class OffloadingActionBuilder final {
/// compilation.
bool CompileHostOnly = false;
bool CompileDeviceOnly = false;
+ bool EmitLLVM = false;
+ bool EmitAsm = false;
/// List of GPU architectures to use in this compilation.
SmallVector<CudaArch, 4> GpuArchList;
@@ -2324,6 +2350,10 @@ class OffloadingActionBuilder final {
/// Flag for -fgpu-rdc.
bool Relocatable = false;
+
+ /// Default GPU architecture if there's no one specified.
+ CudaArch DefaultCudaArch = CudaArch::UNKNOWN;
+
public:
CudaActionBuilderBase(Compilation &C, DerivedArgList &Args,
const Driver::InputList &Inputs,
@@ -2475,6 +2505,8 @@ class OffloadingActionBuilder final {
CompileDeviceOnly = PartialCompilationArg &&
PartialCompilationArg->getOption().matches(
options::OPT_cuda_device_only);
+ EmitLLVM = Args.getLastArg(options::OPT_emit_llvm);
+ EmitAsm = Args.getLastArg(options::OPT_S);
// Collect all cuda_gpu_arch parameters, removing duplicates.
std::set<CudaArch> GpuArchs;
@@ -2511,7 +2543,7 @@ class OffloadingActionBuilder final {
// supported GPUs. sm_20 code should work correctly, if
// suboptimally, on all newer GPUs.
if (GpuArchList.empty())
- GpuArchList.push_back(CudaArch::SM_20);
+ GpuArchList.push_back(DefaultCudaArch);
return Error;
}
@@ -2523,7 +2555,9 @@ class OffloadingActionBuilder final {
public:
CudaActionBuilder(Compilation &C, DerivedArgList &Args,
const Driver::InputList &Inputs)
- : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_Cuda) {}
+ : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_Cuda) {
+ DefaultCudaArch = CudaArch::SM_20;
+ }
ActionBuilderReturnCode
getDeviceDependences(OffloadAction::DeviceDependences &DA,
@@ -2638,7 +2672,9 @@ class OffloadingActionBuilder final {
public:
HIPActionBuilder(Compilation &C, DerivedArgList &Args,
const Driver::InputList &Inputs)
- : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) {}
+ : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) {
+ DefaultCudaArch = CudaArch::GFX803;
+ }
bool canUseBundlerUnbundler() const override { return true; }
@@ -2661,7 +2697,8 @@ class OffloadingActionBuilder final {
assert(!CompileHostOnly &&
"Not expecting CUDA actions in host-only compilation.");
- if (!Relocatable && CurPhase == phases::Backend) {
+ if (!Relocatable && CurPhase == phases::Backend && !EmitLLVM &&
+ !EmitAsm) {
// If we are in backend phase, we attempt to generate the fat binary.
// We compile each arch to IR and use a link action to generate code
// object containing ISA. Then we use a special "link" action to create
@@ -2729,7 +2766,8 @@ class OffloadingActionBuilder final {
A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A,
AssociatedOffloadKind);
- return ABRT_Success;
+ return (CompileDeviceOnly && CurPhase == FinalPhase) ? ABRT_Ignore_Host
+ : ABRT_Success;
}
void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {
@@ -2870,7 +2908,7 @@ class OffloadingActionBuilder final {
OpenMPDeviceActions.clear();
}
- void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {
+ void appendLinkActions(ActionList &AL) override {
assert(ToolChains.size() == DeviceLinkerInputs.size() &&
"Toolchains and linker inputs sizes do not match.");
@@ -2879,12 +2917,18 @@ class OffloadingActionBuilder final {
for (auto &LI : DeviceLinkerInputs) {
auto *DeviceLinkAction =
C.MakeAction<LinkJobAction>(LI, types::TY_Image);
- DA.add(*DeviceLinkAction, **TC, /*BoundArch=*/nullptr,
- Action::OFK_OpenMP);
+ OffloadAction::DeviceDependences DeviceLinkDeps;
+ DeviceLinkDeps.add(*DeviceLinkAction, **TC, /*BoundArch=*/nullptr,
+ Action::OFK_OpenMP);
+ AL.push_back(C.MakeAction<OffloadAction>(DeviceLinkDeps,
+ DeviceLinkAction->getType()));
++TC;
}
+ DeviceLinkerInputs.clear();
}
+ void appendLinkDependences(OffloadAction::DeviceDependences &DA) override {}
+
bool initialize() override {
// Get the OpenMP toolchains. If we don't get any, the action builder will
// know there is nothing to do related to OpenMP offloading.
@@ -3088,7 +3132,8 @@ public:
// the resulting list. Otherwise, just append the device actions. For
// device only compilation, HostAction is a null pointer, therefore only do
// this when HostAction is not a null pointer.
- if (CanUseBundler && HostAction && !OffloadAL.empty()) {
+ if (CanUseBundler && HostAction &&
+ HostAction->getType() != types::TY_Nothing && !OffloadAL.empty()) {
// Add the host action to the list in order to create the bundling action.
OffloadAL.push_back(HostAction);
@@ -3108,6 +3153,25 @@ public:
return false;
}
+ Action* makeHostLinkAction() {
+ // Build a list of device linking actions.
+ ActionList DeviceAL;
+ for (DeviceActionBuilder *SB : SpecializedBuilders) {
+ if (!SB->isValid())
+ continue;
+ SB->appendLinkActions(DeviceAL);
+ }
+
+ if (DeviceAL.empty())
+ return nullptr;
+
+ // Create wrapper bitcode from the result of device link actions and compile
+ // it to an object which will be added to the host link command.
+ auto *BC = C.MakeAction<OffloadWrapperJobAction>(DeviceAL, types::TY_LLVM_BC);
+ auto *ASM = C.MakeAction<BackendJobAction>(BC, types::TY_PP_Asm);
+ return C.MakeAction<AssembleJobAction>(ASM, types::TY_Object);
+ }
+
/// Processes the host linker action. This currently consists of replacing it
/// with an offload action if there are device link objects and propagate to
/// the host action all the offload kinds used in the current compilation. The
@@ -3148,63 +3212,9 @@ public:
};
} // anonymous namespace.
-void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
- const InputList &Inputs, ActionList &Actions) const {
- llvm::PrettyStackTraceString CrashInfo("Building compilation actions");
-
- if (!SuppressMissingInputWarning && Inputs.empty()) {
- Diag(clang::diag::err_drv_no_input_files);
- return;
- }
-
- Arg *FinalPhaseArg;
- phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg);
-
- if (FinalPhase == phases::Link) {
- if (Args.hasArg(options::OPT_emit_llvm))
- Diag(clang::diag::err_drv_emit_llvm_link);
- if (IsCLMode() && LTOMode != LTOK_None &&
- !Args.getLastArgValue(options::OPT_fuse_ld_EQ).equals_lower("lld"))
- Diag(clang::diag::err_drv_lto_without_lld);
- }
-
- // Reject -Z* at the top level, these options should never have been exposed
- // by gcc.
- if (Arg *A = Args.getLastArg(options::OPT_Z_Joined))
- Diag(clang::diag::err_drv_use_of_Z_option) << A->getAsString(Args);
-
- // Diagnose misuse of /Fo.
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fo)) {
- StringRef V = A->getValue();
- if (Inputs.size() > 1 && !V.empty() &&
- !llvm::sys::path::is_separator(V.back())) {
- // Check whether /Fo tries to name an output file for multiple inputs.
- Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources)
- << A->getSpelling() << V;
- Args.eraseArg(options::OPT__SLASH_Fo);
- }
- }
-
- // Diagnose misuse of /Fa.
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fa)) {
- StringRef V = A->getValue();
- if (Inputs.size() > 1 && !V.empty() &&
- !llvm::sys::path::is_separator(V.back())) {
- // Check whether /Fa tries to name an asm file for multiple inputs.
- Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources)
- << A->getSpelling() << V;
- Args.eraseArg(options::OPT__SLASH_Fa);
- }
- }
-
- // Diagnose misuse of /o.
- if (Arg *A = Args.getLastArg(options::OPT__SLASH_o)) {
- if (A->getValue()[0] == '\0') {
- // It has to have a value.
- Diag(clang::diag::err_drv_missing_argument) << A->getSpelling() << 1;
- Args.eraseArg(options::OPT__SLASH_o);
- }
- }
+void Driver::handleArguments(Compilation &C, DerivedArgList &Args,
+ const InputList &Inputs,
+ ActionList &Actions) const {
// Ignore /Yc/Yu if both /Yc and /Yu passed but with different filenames.
Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc);
@@ -3220,6 +3230,18 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
Args.eraseArg(options::OPT__SLASH_Yc);
YcArg = nullptr;
}
+
+ Arg *FinalPhaseArg;
+ phases::ID FinalPhase = getFinalPhase(Args, &FinalPhaseArg);
+
+ if (FinalPhase == phases::Link) {
+ if (Args.hasArg(options::OPT_emit_llvm))
+ Diag(clang::diag::err_drv_emit_llvm_link);
+ if (IsCLMode() && LTOMode != LTOK_None &&
+ !Args.getLastArgValue(options::OPT_fuse_ld_EQ).equals_lower("lld"))
+ Diag(clang::diag::err_drv_lto_without_lld);
+ }
+
if (FinalPhase == phases::Preprocess || Args.hasArg(options::OPT__SLASH_Y_)) {
// If only preprocessing or /Y- is used, all pch handling is disabled.
// Rather than check for it everywhere, just remove clang-cl pch-related
@@ -3230,20 +3252,14 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
YcArg = YuArg = nullptr;
}
- // Builder to be used to build offloading actions.
- OffloadingActionBuilder OffloadBuilder(C, Args, Inputs);
-
- // Construct the actions to perform.
- HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr;
- ActionList LinkerInputs;
-
- llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PL;
+ unsigned LastPLSize = 0;
for (auto &I : Inputs) {
types::ID InputType = I.first;
const Arg *InputArg = I.second;
- PL.clear();
+ llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PL;
types::getCompilationPhases(InputType, PL);
+ LastPLSize = PL.size();
// If the first step comes after the final phase we are doing as part of
// this compilation, warn the user about it.
@@ -3267,7 +3283,10 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
// Special case '-E' warning on a previously preprocessed file to make
// more sense.
else if (InitialPhase == phases::Compile &&
- FinalPhase == phases::Preprocess &&
+ (Args.getLastArg(options::OPT__SLASH_EP,
+ options::OPT__SLASH_P) ||
+ Args.getLastArg(options::OPT_E) ||
+ Args.getLastArg(options::OPT_M, options::OPT_MM)) &&
getPreprocessedType(InputType) == types::TY_INVALID)
Diag(clang::diag::warn_drv_preprocessed_input_file_unused)
<< InputArg->getAsString(Args) << !!FinalPhaseArg
@@ -3287,8 +3306,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PCHPL;
types::getCompilationPhases(HeaderType, PCHPL);
// Build the pipeline for the pch file.
- Action *ClangClPch =
- C.MakeAction<InputAction>(*InputArg, HeaderType);
+ Action *ClangClPch = C.MakeAction<InputAction>(*InputArg, HeaderType);
for (phases::ID Phase : PCHPL)
ClangClPch = ConstructPhaseAction(C, Args, Phase, ClangClPch);
assert(ClangClPch);
@@ -3300,6 +3318,85 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
// probably not be considered successful either.
}
}
+ }
+
+ // If we are linking, claim any options which are obviously only used for
+ // compilation.
+ // FIXME: Understand why the last Phase List length is used here.
+ if (FinalPhase == phases::Link && LastPLSize == 1) {
+ Args.ClaimAllArgs(options::OPT_CompileOnly_Group);
+ Args.ClaimAllArgs(options::OPT_cl_compile_Group);
+ }
+}
+
+void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
+ const InputList &Inputs, ActionList &Actions) const {
+ llvm::PrettyStackTraceString CrashInfo("Building compilation actions");
+
+ if (!SuppressMissingInputWarning && Inputs.empty()) {
+ Diag(clang::diag::err_drv_no_input_files);
+ return;
+ }
+
+ // Reject -Z* at the top level, these options should never have been exposed
+ // by gcc.
+ if (Arg *A = Args.getLastArg(options::OPT_Z_Joined))
+ Diag(clang::diag::err_drv_use_of_Z_option) << A->getAsString(Args);
+
+ // Diagnose misuse of /Fo.
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fo)) {
+ StringRef V = A->getValue();
+ if (Inputs.size() > 1 && !V.empty() &&
+ !llvm::sys::path::is_separator(V.back())) {
+ // Check whether /Fo tries to name an output file for multiple inputs.
+ Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources)
+ << A->getSpelling() << V;
+ Args.eraseArg(options::OPT__SLASH_Fo);
+ }
+ }
+
+ // Diagnose misuse of /Fa.
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_Fa)) {
+ StringRef V = A->getValue();
+ if (Inputs.size() > 1 && !V.empty() &&
+ !llvm::sys::path::is_separator(V.back())) {
+ // Check whether /Fa tries to name an asm file for multiple inputs.
+ Diag(clang::diag::err_drv_out_file_argument_with_multiple_sources)
+ << A->getSpelling() << V;
+ Args.eraseArg(options::OPT__SLASH_Fa);
+ }
+ }
+
+ // Diagnose misuse of /o.
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_o)) {
+ if (A->getValue()[0] == '\0') {
+ // It has to have a value.
+ Diag(clang::diag::err_drv_missing_argument) << A->getSpelling() << 1;
+ Args.eraseArg(options::OPT__SLASH_o);
+ }
+ }
+
+ handleArguments(C, Args, Inputs, Actions);
+
+ // Builder to be used to build offloading actions.
+ OffloadingActionBuilder OffloadBuilder(C, Args, Inputs);
+
+ // Construct the actions to perform.
+ HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr;
+ ActionList LinkerInputs;
+ ActionList MergerInputs;
+
+ for (auto &I : Inputs) {
+ types::ID InputType = I.first;
+ const Arg *InputArg = I.second;
+
+ llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PL;
+ types::getCompilationPhases(*this, Args, InputType, PL);
+ if (PL.empty())
+ continue;
+
+ llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> FullPL;
+ types::getCompilationPhases(InputType, FullPL);
// Build the pipeline for this file.
Action *Current = C.MakeAction<InputAction>(*InputArg, InputType);
@@ -3309,28 +3406,33 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
if (OffloadBuilder.addHostDependenceToDeviceActions(Current, InputArg))
break;
- for (SmallVectorImpl<phases::ID>::iterator i = PL.begin(), e = PL.end();
- i != e; ++i) {
- phases::ID Phase = *i;
-
- // We are done if this step is past what the user requested.
- if (Phase > FinalPhase)
- break;
+ for (phases::ID Phase : PL) {
// Add any offload action the host action depends on.
Current = OffloadBuilder.addDeviceDependencesToHostAction(
- Current, InputArg, Phase, FinalPhase, PL);
+ Current, InputArg, Phase, PL.back(), FullPL);
if (!Current)
break;
// Queue linker inputs.
if (Phase == phases::Link) {
- assert((i + 1) == e && "linking must be final compilation step.");
+ assert(Phase == PL.back() && "linking must be final compilation step.");
LinkerInputs.push_back(Current);
Current = nullptr;
break;
}
+ // TODO: Consider removing this because the merged may not end up being
+ // the final Phase in the pipeline. Perhaps the merged could just merge
+ // and then pass an artifact of some sort to the Link Phase.
+ // Queue merger inputs.
+ if (Phase == phases::IfsMerge) {
+ assert(Phase == PL.back() && "merging must be final compilation step.");
+ MergerInputs.push_back(Current);
+ Current = nullptr;
+ break;
+ }
+
// Each precompiled header file after a module file action is a module
// header of that same module file, rather than being compiled to a
// separate PCH.
@@ -3375,17 +3477,17 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
// Add a link action if necessary.
if (!LinkerInputs.empty()) {
+ if (Action *Wrapper = OffloadBuilder.makeHostLinkAction())
+ LinkerInputs.push_back(Wrapper);
Action *LA = C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image);
LA = OffloadBuilder.processHostLinkAction(LA);
Actions.push_back(LA);
}
- // If we are linking, claim any options which are obviously only used for
- // compilation.
- if (FinalPhase == phases::Link && PL.size() == 1) {
- Args.ClaimAllArgs(options::OPT_CompileOnly_Group);
- Args.ClaimAllArgs(options::OPT_cl_compile_Group);
- }
+ // Add an interface stubs merge action if necessary.
+ if (!MergerInputs.empty())
+ Actions.push_back(
+ C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image));
// If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a custom
// Compile phase that prints out supported cpu models and quits.
@@ -3423,10 +3525,14 @@ Action *Driver::ConstructPhaseAction(
switch (Phase) {
case phases::Link:
llvm_unreachable("link action invalid here.");
+ case phases::IfsMerge:
+ llvm_unreachable("ifsmerge action invalid here.");
case phases::Preprocess: {
types::ID OutputTy;
- // -{M, MM} alter the output type.
- if (Args.hasArg(options::OPT_M, options::OPT_MM)) {
+ // -M and -MM specify the dependency file name by altering the output type,
+ // -if -MD and -MMD are not specified.
+ if (Args.hasArg(options::OPT_M, options::OPT_MM) &&
+ !Args.hasArg(options::OPT_MD, options::OPT_MMD)) {
OutputTy = types::TY_Dependencies;
} else {
OutputTy = Input->getType();
@@ -3474,7 +3580,7 @@ Action *Driver::ConstructPhaseAction(
if (Args.hasArg(options::OPT_rewrite_legacy_objc))
return C.MakeAction<CompileJobAction>(Input,
types::TY_RewrittenLegacyObjC);
- if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto))
+ if (Args.hasArg(options::OPT__analyze))
return C.MakeAction<AnalyzeJobAction>(Input, types::TY_Plist);
if (Args.hasArg(options::OPT__migrate))
return C.MakeAction<MigrateJobAction>(Input, types::TY_Remap);
@@ -3484,8 +3590,8 @@ Action *Driver::ConstructPhaseAction(
return C.MakeAction<CompileJobAction>(Input, types::TY_ModuleFile);
if (Args.hasArg(options::OPT_verify_pch))
return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing);
- if (Args.hasArg(options::OPT_emit_iterface_stubs))
- return C.MakeAction<CompileJobAction>(Input, types::TY_IFS);
+ if (Args.hasArg(options::OPT_emit_interface_stubs))
+ return C.MakeAction<CompileJobAction>(Input, types::TY_IFS_CPP);
return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC);
}
case phases::Backend: {
@@ -3759,18 +3865,8 @@ class ToolSelector final {
if (!AJ || !BJ)
return nullptr;
- // Retrieve the compile job, backend action must always be preceded by one.
- ActionList CompileJobOffloadActions;
- auto *CJ = getPrevDependentAction(BJ->getInputs(), CompileJobOffloadActions,
- /*CanBeCollapsed=*/false);
- if (!AJ || !BJ || !CJ)
- return nullptr;
-
- assert(isa<CompileJobAction>(CJ) &&
- "Expecting compile job preceding backend job.");
-
- // Get compiler tool.
- const Tool *T = TC.SelectTool(*CJ);
+ // Get backend tool.
+ const Tool *T = TC.SelectTool(*BJ);
if (!T)
return nullptr;
@@ -4175,6 +4271,13 @@ InputInfo Driver::BuildJobsForActionNoCache(
A->getOffloadingDeviceKind(), TC->getTriple().normalize(),
/*CreatePrefixForHost=*/!!A->getOffloadingHostActiveKinds() &&
!AtTopLevel);
+ if (isa<OffloadWrapperJobAction>(JA)) {
+ OffloadingPrefix += "-wrapper";
+ if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
+ BaseInput = FinalOutput->getValue();
+ else
+ BaseInput = getDefaultImageName();
+ }
Result = InputInfo(A, GetNamedOutputPath(C, *JA, BaseInput, BoundArch,
AtTopLevel, MultipleArchs,
OffloadingPrefix),
@@ -4358,11 +4461,22 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
MakeCLOutputFilename(C.getArgs(), "", BaseName, types::TY_Image);
} else {
SmallString<128> Output(getDefaultImageName());
+ // HIP image for device compilation with -fno-gpu-rdc is per compilation
+ // unit.
+ bool IsHIPNoRDC = JA.getOffloadingDeviceKind() == Action::OFK_HIP &&
+ !C.getArgs().hasFlag(options::OPT_fgpu_rdc,
+ options::OPT_fno_gpu_rdc, false);
+ if (IsHIPNoRDC) {
+ Output = BaseName;
+ llvm::sys::path::replace_extension(Output, "");
+ }
Output += OffloadingPrefix;
if (MultipleArchs && !BoundArch.empty()) {
Output += "-";
Output.append(BoundArch);
}
+ if (IsHIPNoRDC)
+ Output += ".out";
NamedOutput = C.getArgs().MakeArgString(Output.c_str());
}
} else if (JA.getType() == types::TY_PCH && IsCLMode()) {
@@ -4586,152 +4700,152 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
if (!TC) {
switch (Target.getOS()) {
case llvm::Triple::Haiku:
- TC = llvm::make_unique<toolchains::Haiku>(*this, Target, Args);
+ TC = std::make_unique<toolchains::Haiku>(*this, Target, Args);
break;
case llvm::Triple::Ananas:
- TC = llvm::make_unique<toolchains::Ananas>(*this, Target, Args);
+ TC = std::make_unique<toolchains::Ananas>(*this, Target, Args);
break;
case llvm::Triple::CloudABI:
- TC = llvm::make_unique<toolchains::CloudABI>(*this, Target, Args);
+ TC = std::make_unique<toolchains::CloudABI>(*this, Target, Args);
break;
case llvm::Triple::Darwin:
case llvm::Triple::MacOSX:
case llvm::Triple::IOS:
case llvm::Triple::TvOS:
case llvm::Triple::WatchOS:
- TC = llvm::make_unique<toolchains::DarwinClang>(*this, Target, Args);
+ TC = std::make_unique<toolchains::DarwinClang>(*this, Target, Args);
break;
case llvm::Triple::DragonFly:
- TC = llvm::make_unique<toolchains::DragonFly>(*this, Target, Args);
+ TC = std::make_unique<toolchains::DragonFly>(*this, Target, Args);
break;
case llvm::Triple::OpenBSD:
- TC = llvm::make_unique<toolchains::OpenBSD>(*this, Target, Args);
+ TC = std::make_unique<toolchains::OpenBSD>(*this, Target, Args);
break;
case llvm::Triple::NetBSD:
- TC = llvm::make_unique<toolchains::NetBSD>(*this, Target, Args);
+ TC = std::make_unique<toolchains::NetBSD>(*this, Target, Args);
break;
case llvm::Triple::FreeBSD:
- TC = llvm::make_unique<toolchains::FreeBSD>(*this, Target, Args);
+ TC = std::make_unique<toolchains::FreeBSD>(*this, Target, Args);
break;
case llvm::Triple::Minix:
- TC = llvm::make_unique<toolchains::Minix>(*this, Target, Args);
+ TC = std::make_unique<toolchains::Minix>(*this, Target, Args);
break;
case llvm::Triple::Linux:
case llvm::Triple::ELFIAMCU:
if (Target.getArch() == llvm::Triple::hexagon)
- TC = llvm::make_unique<toolchains::HexagonToolChain>(*this, Target,
+ TC = std::make_unique<toolchains::HexagonToolChain>(*this, Target,
Args);
else if ((Target.getVendor() == llvm::Triple::MipsTechnologies) &&
!Target.hasEnvironment())
- TC = llvm::make_unique<toolchains::MipsLLVMToolChain>(*this, Target,
+ TC = std::make_unique<toolchains::MipsLLVMToolChain>(*this, Target,
Args);
else if (Target.getArch() == llvm::Triple::ppc ||
Target.getArch() == llvm::Triple::ppc64 ||
Target.getArch() == llvm::Triple::ppc64le)
- TC = llvm::make_unique<toolchains::PPCLinuxToolChain>(*this, Target,
+ TC = std::make_unique<toolchains::PPCLinuxToolChain>(*this, Target,
Args);
else
- TC = llvm::make_unique<toolchains::Linux>(*this, Target, Args);
+ TC = std::make_unique<toolchains::Linux>(*this, Target, Args);
break;
case llvm::Triple::NaCl:
- TC = llvm::make_unique<toolchains::NaClToolChain>(*this, Target, Args);
+ TC = std::make_unique<toolchains::NaClToolChain>(*this, Target, Args);
break;
case llvm::Triple::Fuchsia:
- TC = llvm::make_unique<toolchains::Fuchsia>(*this, Target, Args);
+ TC = std::make_unique<toolchains::Fuchsia>(*this, Target, Args);
break;
case llvm::Triple::Solaris:
- TC = llvm::make_unique<toolchains::Solaris>(*this, Target, Args);
+ TC = std::make_unique<toolchains::Solaris>(*this, Target, Args);
break;
case llvm::Triple::AMDHSA:
case llvm::Triple::AMDPAL:
case llvm::Triple::Mesa3D:
- TC = llvm::make_unique<toolchains::AMDGPUToolChain>(*this, Target, Args);
+ TC = std::make_unique<toolchains::AMDGPUToolChain>(*this, Target, Args);
break;
case llvm::Triple::Win32:
switch (Target.getEnvironment()) {
default:
if (Target.isOSBinFormatELF())
- TC = llvm::make_unique<toolchains::Generic_ELF>(*this, Target, Args);
+ TC = std::make_unique<toolchains::Generic_ELF>(*this, Target, Args);
else if (Target.isOSBinFormatMachO())
- TC = llvm::make_unique<toolchains::MachO>(*this, Target, Args);
+ TC = std::make_unique<toolchains::MachO>(*this, Target, Args);
else
- TC = llvm::make_unique<toolchains::Generic_GCC>(*this, Target, Args);
+ TC = std::make_unique<toolchains::Generic_GCC>(*this, Target, Args);
break;
case llvm::Triple::GNU:
- TC = llvm::make_unique<toolchains::MinGW>(*this, Target, Args);
+ TC = std::make_unique<toolchains::MinGW>(*this, Target, Args);
break;
case llvm::Triple::Itanium:
- TC = llvm::make_unique<toolchains::CrossWindowsToolChain>(*this, Target,
+ TC = std::make_unique<toolchains::CrossWindowsToolChain>(*this, Target,
Args);
break;
case llvm::Triple::MSVC:
case llvm::Triple::UnknownEnvironment:
if (Args.getLastArgValue(options::OPT_fuse_ld_EQ)
.startswith_lower("bfd"))
- TC = llvm::make_unique<toolchains::CrossWindowsToolChain>(
+ TC = std::make_unique<toolchains::CrossWindowsToolChain>(
*this, Target, Args);
else
TC =
- llvm::make_unique<toolchains::MSVCToolChain>(*this, Target, Args);
+ std::make_unique<toolchains::MSVCToolChain>(*this, Target, Args);
break;
}
break;
case llvm::Triple::PS4:
- TC = llvm::make_unique<toolchains::PS4CPU>(*this, Target, Args);
+ TC = std::make_unique<toolchains::PS4CPU>(*this, Target, Args);
break;
case llvm::Triple::Contiki:
- TC = llvm::make_unique<toolchains::Contiki>(*this, Target, Args);
+ TC = std::make_unique<toolchains::Contiki>(*this, Target, Args);
break;
case llvm::Triple::Hurd:
- TC = llvm::make_unique<toolchains::Hurd>(*this, Target, Args);
+ TC = std::make_unique<toolchains::Hurd>(*this, Target, Args);
break;
default:
// Of these targets, Hexagon is the only one that might have
// an OS of Linux, in which case it got handled above already.
switch (Target.getArch()) {
case llvm::Triple::tce:
- TC = llvm::make_unique<toolchains::TCEToolChain>(*this, Target, Args);
+ TC = std::make_unique<toolchains::TCEToolChain>(*this, Target, Args);
break;
case llvm::Triple::tcele:
- TC = llvm::make_unique<toolchains::TCELEToolChain>(*this, Target, Args);
+ TC = std::make_unique<toolchains::TCELEToolChain>(*this, Target, Args);
break;
case llvm::Triple::hexagon:
- TC = llvm::make_unique<toolchains::HexagonToolChain>(*this, Target,
+ TC = std::make_unique<toolchains::HexagonToolChain>(*this, Target,
Args);
break;
case llvm::Triple::lanai:
- TC = llvm::make_unique<toolchains::LanaiToolChain>(*this, Target, Args);
+ TC = std::make_unique<toolchains::LanaiToolChain>(*this, Target, Args);
break;
case llvm::Triple::xcore:
- TC = llvm::make_unique<toolchains::XCoreToolChain>(*this, Target, Args);
+ TC = std::make_unique<toolchains::XCoreToolChain>(*this, Target, Args);
break;
case llvm::Triple::wasm32:
case llvm::Triple::wasm64:
- TC = llvm::make_unique<toolchains::WebAssembly>(*this, Target, Args);
+ TC = std::make_unique<toolchains::WebAssembly>(*this, Target, Args);
break;
case llvm::Triple::avr:
- TC = llvm::make_unique<toolchains::AVRToolChain>(*this, Target, Args);
+ TC = std::make_unique<toolchains::AVRToolChain>(*this, Target, Args);
break;
case llvm::Triple::msp430:
TC =
- llvm::make_unique<toolchains::MSP430ToolChain>(*this, Target, Args);
+ std::make_unique<toolchains::MSP430ToolChain>(*this, Target, Args);
break;
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
- TC = llvm::make_unique<toolchains::RISCVToolChain>(*this, Target, Args);
+ TC = std::make_unique<toolchains::RISCVToolChain>(*this, Target, Args);
break;
default:
if (Target.getVendor() == llvm::Triple::Myriad)
- TC = llvm::make_unique<toolchains::MyriadToolChain>(*this, Target,
+ TC = std::make_unique<toolchains::MyriadToolChain>(*this, Target,
Args);
else if (toolchains::BareMetal::handlesTarget(Target))
- TC = llvm::make_unique<toolchains::BareMetal>(*this, Target, Args);
+ TC = std::make_unique<toolchains::BareMetal>(*this, Target, Args);
else if (Target.isOSBinFormatELF())
- TC = llvm::make_unique<toolchains::Generic_ELF>(*this, Target, Args);
+ TC = std::make_unique<toolchains::Generic_ELF>(*this, Target, Args);
else if (Target.isOSBinFormatMachO())
- TC = llvm::make_unique<toolchains::MachO>(*this, Target, Args);
+ TC = std::make_unique<toolchains::MachO>(*this, Target, Args);
else
- TC = llvm::make_unique<toolchains::Generic_GCC>(*this, Target, Args);
+ TC = std::make_unique<toolchains::Generic_GCC>(*this, Target, Args);
}
}
}
diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp
index 1ad188838eda..67d4198d222a 100644
--- a/lib/Driver/DriverOptions.cpp
+++ b/lib/Driver/DriverOptions.cpp
@@ -39,14 +39,17 @@ public:
}
-std::unique_ptr<OptTable> clang::driver::createDriverOptTable() {
- auto Result = llvm::make_unique<DriverOptTable>();
- // Options.inc is included in DriverOptions.cpp, and calls OptTable's
- // addValues function.
- // Opt is a variable used in the code fragment in Options.inc.
- OptTable &Opt = *Result;
+const llvm::opt::OptTable &clang::driver::getDriverOptTable() {
+ static const DriverOptTable *Table = []() {
+ auto Result = std::make_unique<DriverOptTable>();
+ // Options.inc is included in DriverOptions.cpp, and calls OptTable's
+ // addValues function.
+ // Opt is a variable used in the code fragment in Options.inc.
+ OptTable &Opt = *Result;
#define OPTTABLE_ARG_INIT
#include "clang/Driver/Options.inc"
#undef OPTTABLE_ARG_INIT
- return std::move(Result);
+ return Result.release();
+ }();
+ return *Table;
}
diff --git a/lib/Driver/Phases.cpp b/lib/Driver/Phases.cpp
index 5b776c63f713..01598c59bd9e 100644
--- a/lib/Driver/Phases.cpp
+++ b/lib/Driver/Phases.cpp
@@ -20,6 +20,7 @@ const char *phases::getPhaseName(ID Id) {
case Backend: return "backend";
case Assemble: return "assembler";
case Link: return "linker";
+ case IfsMerge: return "ifsmerger";
}
llvm_unreachable("Invalid phase id.");
diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp
index 6b6a9feec42c..cc6c5e6ef438 100644
--- a/lib/Driver/SanitizerArgs.cpp
+++ b/lib/Driver/SanitizerArgs.cpp
@@ -46,7 +46,8 @@ static const SanitizerMask SupportsCoverage =
SanitizerKind::Undefined | SanitizerKind::Integer |
SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
SanitizerKind::DataFlow | SanitizerKind::Fuzzer |
- SanitizerKind::FuzzerNoLink | SanitizerKind::FloatDivideByZero;
+ SanitizerKind::FuzzerNoLink | SanitizerKind::FloatDivideByZero |
+ SanitizerKind::SafeStack | SanitizerKind::ShadowCallStack;
static const SanitizerMask RecoverableByDefault =
SanitizerKind::Undefined | SanitizerKind::Integer |
SanitizerKind::ImplicitConversion | SanitizerKind::Nullability |
@@ -635,6 +636,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
D.Diag(diag::err_drv_argument_not_allowed_with)
<< "-fsanitize-cfi-cross-dso"
<< "-fsanitize-cfi-icall-generalize-pointers";
+
+ CfiCanonicalJumpTables =
+ Args.hasFlag(options::OPT_fsanitize_cfi_canonical_jump_tables,
+ options::OPT_fno_sanitize_cfi_canonical_jump_tables, true);
}
Stats = Args.hasFlag(options::OPT_fsanitize_stats,
@@ -824,9 +829,15 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
SafeStackRuntime = !TC.getTriple().isOSFuchsia();
}
+ LinkRuntimes =
+ Args.hasFlag(options::OPT_fsanitize_link_runtime,
+ options::OPT_fno_sanitize_link_runtime, LinkRuntimes);
+
// Parse -link-cxx-sanitizer flag.
- LinkCXXRuntimes =
- Args.hasArg(options::OPT_fsanitize_link_cxx_runtime) || D.CCCIsCXX();
+ LinkCXXRuntimes = Args.hasArg(options::OPT_fsanitize_link_cxx_runtime,
+ options::OPT_fno_sanitize_link_cxx_runtime,
+ LinkCXXRuntimes) ||
+ D.CCCIsCXX();
// Finally, initialize the set of available and recoverable sanitizers.
Sanitizers.Mask |= Kinds;
@@ -862,6 +873,18 @@ static void addIncludeLinkerOption(const ToolChain &TC,
CmdArgs.push_back(Args.MakeArgString(LinkerOptionFlag));
}
+static bool hasTargetFeatureMTE(const llvm::opt::ArgStringList &CmdArgs) {
+ for (auto Start = CmdArgs.begin(), End = CmdArgs.end(); Start != End; ++Start) {
+ auto It = std::find(Start, End, StringRef("+mte"));
+ if (It == End)
+ break;
+ if (It > Start && *std::prev(It) == StringRef("-target-feature"))
+ return true;
+ Start = It;
+ }
+ return false;
+}
+
void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs,
types::ID InputType) const {
@@ -969,6 +992,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
if (CfiICallGeneralizePointers)
CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers");
+ if (CfiCanonicalJumpTables)
+ CmdArgs.push_back("-fsanitize-cfi-canonical-jump-tables");
+
if (Stats)
CmdArgs.push_back("-fsanitize-stats");
@@ -1006,6 +1032,11 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
CmdArgs.push_back(Args.MakeArgString("hwasan-abi=" + HwasanAbi));
}
+ if (Sanitizers.has(SanitizerKind::HWAddress)) {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("+tagged-globals");
+ }
+
// MSan: Workaround for PR16386.
// ASan: This is mainly to help LSan with cases such as
// https://github.com/google/sanitizers/issues/373
@@ -1024,6 +1055,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
Sanitizers.Mask & CFIClasses)
<< "-fvisibility=";
}
+
+ if (Sanitizers.has(SanitizerKind::MemTag) && !hasTargetFeatureMTE(CmdArgs))
+ TC.getDriver().Diag(diag::err_stack_tagging_requires_hardware_feature);
}
SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A,
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index b1fddb0af55d..357a5106ab39 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -10,6 +10,7 @@
#include "InputInfo.h"
#include "ToolChains/Arch/ARM.h"
#include "ToolChains/Clang.h"
+#include "ToolChains/InterfaceStubs.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Sanitizers.h"
#include "clang/Config/config.h"
@@ -279,17 +280,32 @@ Tool *ToolChain::getLink() const {
return Link.get();
}
+Tool *ToolChain::getIfsMerge() const {
+ if (!IfsMerge)
+ IfsMerge.reset(new tools::ifstool::Merger(*this));
+ return IfsMerge.get();
+}
+
Tool *ToolChain::getOffloadBundler() const {
if (!OffloadBundler)
OffloadBundler.reset(new tools::OffloadBundler(*this));
return OffloadBundler.get();
}
+Tool *ToolChain::getOffloadWrapper() const {
+ if (!OffloadWrapper)
+ OffloadWrapper.reset(new tools::OffloadWrapper(*this));
+ return OffloadWrapper.get();
+}
+
Tool *ToolChain::getTool(Action::ActionClass AC) const {
switch (AC) {
case Action::AssembleJobClass:
return getAssemble();
+ case Action::IfsMergeJobClass:
+ return getIfsMerge();
+
case Action::LinkJobClass:
return getLink();
@@ -314,6 +330,9 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
case Action::OffloadBundlingJobClass:
case Action::OffloadUnbundlingJobClass:
return getOffloadBundler();
+
+ case Action::OffloadWrapperJobClass:
+ return getOffloadWrapper();
}
llvm_unreachable("Invalid tool kind.");
@@ -832,6 +851,16 @@ void ToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
DriverArgs.AddAllArgs(CC1Args, options::OPT_stdlib_EQ);
}
+void ToolChain::AddClangCXXStdlibIsystemArgs(
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ DriverArgs.ClaimAllArgs(options::OPT_stdlibxx_isystem);
+ if (!DriverArgs.hasArg(options::OPT_nostdincxx))
+ for (const auto &P :
+ DriverArgs.getAllArgValues(options::OPT_stdlibxx_isystem))
+ addSystemInclude(DriverArgs, CC1Args, P);
+}
+
bool ToolChain::ShouldLinkCXXStdlib(const llvm::opt::ArgList &Args) const {
return getDriver().CCCIsCXX() &&
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
@@ -913,6 +942,9 @@ SanitizerMask ToolChain::getSupportedSanitizers() const {
if (getTriple().getArch() == llvm::Triple::x86_64 ||
getTriple().getArch() == llvm::Triple::aarch64)
Res |= SanitizerKind::ShadowCallStack;
+ if (getTriple().getArch() == llvm::Triple::aarch64 ||
+ getTriple().getArch() == llvm::Triple::aarch64_be)
+ Res |= SanitizerKind::MemTag;
return Res;
}
diff --git a/lib/Driver/ToolChains/AMDGPU.cpp b/lib/Driver/ToolChains/AMDGPU.cpp
index df4e7ee202bf..71a2c68b4197 100644
--- a/lib/Driver/ToolChains/AMDGPU.cpp
+++ b/lib/Driver/ToolChains/AMDGPU.cpp
@@ -31,7 +31,7 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-shared");
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
+ C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
CmdArgs, Inputs));
}
diff --git a/lib/Driver/ToolChains/AVR.cpp b/lib/Driver/ToolChains/AVR.cpp
index 4a60d9ec589b..e8a3a7b38c31 100644
--- a/lib/Driver/ToolChains/AVR.cpp
+++ b/lib/Driver/ToolChains/AVR.cpp
@@ -144,7 +144,7 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName));
}
- C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
+ C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
CmdArgs, Inputs));
}
diff --git a/lib/Driver/ToolChains/Ananas.cpp b/lib/Driver/ToolChains/Ananas.cpp
index e3511198cb2d..2f11c9739a0e 100644
--- a/lib/Driver/ToolChains/Ananas.cpp
+++ b/lib/Driver/ToolChains/Ananas.cpp
@@ -39,7 +39,7 @@ void ananas::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -123,7 +123,7 @@ void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
// Ananas - Ananas tool chain which can call as(1) and ld(1) directly.
diff --git a/lib/Driver/ToolChains/Arch/AArch64.cpp b/lib/Driver/ToolChains/Arch/AArch64.cpp
index 35d11f4e2d3b..3a5fe6ddeaed 100644
--- a/lib/Driver/ToolChains/Arch/AArch64.cpp
+++ b/lib/Driver/ToolChains/Arch/AArch64.cpp
@@ -12,6 +12,7 @@
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/TargetParser.h"
+#include "llvm/Support/Host.h"
using namespace clang::driver;
using namespace clang::driver::tools;
diff --git a/lib/Driver/ToolChains/Arch/ARM.cpp b/lib/Driver/ToolChains/Arch/ARM.cpp
index d1db583e5280..68a57310ad40 100644
--- a/lib/Driver/ToolChains/Arch/ARM.cpp
+++ b/lib/Driver/ToolChains/Arch/ARM.cpp
@@ -13,6 +13,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/TargetParser.h"
+#include "llvm/Support/Host.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -460,11 +461,12 @@ fp16_fml_fallthrough:
// now just be explicit and disable all known dependent features
// as well.
for (std::string Feature : {
- "vfp2", "vfp2sp", "vfp2d16", "vfp2d16sp",
+ "vfp2", "vfp2sp",
"vfp3", "vfp3sp", "vfp3d16", "vfp3d16sp",
"vfp4", "vfp4sp", "vfp4d16", "vfp4d16sp",
"fp-armv8", "fp-armv8sp", "fp-armv8d16", "fp-armv8d16sp",
"fullfp16", "neon", "crypto", "dotprod", "fp16fml",
+ "mve", "mve.fp",
"fp64", "d32", "fpregs"})
Features.push_back(Args.MakeArgString("-" + Feature));
}
@@ -477,23 +479,35 @@ fp16_fml_fallthrough:
Features.push_back("-crc");
}
- // For Arch >= ARMv8.0: crypto = sha2 + aes
+ // For Arch >= ARMv8.0 && A profile: crypto = sha2 + aes
// FIXME: this needs reimplementation after the TargetParser rewrite
- if (ArchName.find_lower("armv8a") != StringRef::npos ||
- ArchName.find_lower("armv8.1a") != StringRef::npos ||
- ArchName.find_lower("armv8.2a") != StringRef::npos ||
- ArchName.find_lower("armv8.3a") != StringRef::npos ||
- ArchName.find_lower("armv8.4a") != StringRef::npos) {
- if (ArchName.find_lower("+crypto") != StringRef::npos) {
- if (ArchName.find_lower("+nosha2") == StringRef::npos)
- Features.push_back("+sha2");
- if (ArchName.find_lower("+noaes") == StringRef::npos)
- Features.push_back("+aes");
- } else if (ArchName.find_lower("-crypto") != StringRef::npos) {
- if (ArchName.find_lower("+sha2") == StringRef::npos)
- Features.push_back("-sha2");
- if (ArchName.find_lower("+aes") == StringRef::npos)
- Features.push_back("-aes");
+ auto CryptoIt = llvm::find_if(llvm::reverse(Features), [](const StringRef F) {
+ return F.contains("crypto");
+ });
+ if (CryptoIt != Features.rend()) {
+ if (CryptoIt->take_front() == "+") {
+ StringRef ArchSuffix = arm::getLLVMArchSuffixForARM(
+ arm::getARMTargetCPU(CPUName, ArchName, Triple), ArchName, Triple);
+ if (llvm::ARM::parseArchVersion(ArchSuffix) >= 8 &&
+ llvm::ARM::parseArchProfile(ArchSuffix) ==
+ llvm::ARM::ProfileKind::A) {
+ if (ArchName.find_lower("+nosha2") == StringRef::npos &&
+ CPUName.find_lower("+nosha2") == StringRef::npos)
+ Features.push_back("+sha2");
+ if (ArchName.find_lower("+noaes") == StringRef::npos &&
+ CPUName.find_lower("+noaes") == StringRef::npos)
+ Features.push_back("+aes");
+ } else {
+ D.Diag(clang::diag::warn_target_unsupported_extension)
+ << "crypto"
+ << llvm::ARM::getArchName(llvm::ARM::parseArch(ArchSuffix));
+ // With -fno-integrated-as -mfpu=crypto-neon-fp-armv8 some assemblers such as the GNU assembler
+ // will permit the use of crypto instructions as the fpu will override the architecture.
+ // We keep the crypto feature in this case to preserve compatibility.
+ // In all other cases we remove the crypto feature.
+ if (!Args.hasArg(options::OPT_fno_integrated_as))
+ Features.push_back("-crypto");
+ }
}
}
@@ -655,7 +669,7 @@ std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch,
llvm::ARM::ArchKind arm::getLLVMArchKindForARM(StringRef CPU, StringRef Arch,
const llvm::Triple &Triple) {
llvm::ARM::ArchKind ArchKind;
- if (CPU == "generic") {
+ if (CPU == "generic" || CPU.empty()) {
std::string ARMArch = tools::arm::getARMArch(Arch, Triple);
ArchKind = llvm::ARM::parseArch(ARMArch);
if (ArchKind == llvm::ARM::ArchKind::INVALID)
diff --git a/lib/Driver/ToolChains/Arch/Mips.cpp b/lib/Driver/ToolChains/Arch/Mips.cpp
index b512ff64b0c6..7b4dd703c0c7 100644
--- a/lib/Driver/ToolChains/Arch/Mips.cpp
+++ b/lib/Driver/ToolChains/Arch/Mips.cpp
@@ -149,7 +149,8 @@ StringRef mips::getGnuCompatibleMipsABIName(StringRef ABI) {
// Select the MIPS float ABI as determined by -msoft-float, -mhard-float,
// and -mfloat-abi=.
-mips::FloatABI mips::getMipsFloatABI(const Driver &D, const ArgList &Args) {
+mips::FloatABI mips::getMipsFloatABI(const Driver &D, const ArgList &Args,
+ const llvm::Triple &Triple) {
mips::FloatABI ABI = mips::FloatABI::Invalid;
if (Arg *A =
Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
@@ -172,10 +173,15 @@ mips::FloatABI mips::getMipsFloatABI(const Driver &D, const ArgList &Args) {
// If unspecified, choose the default based on the platform.
if (ABI == mips::FloatABI::Invalid) {
- // 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.
- ABI = mips::FloatABI::Hard;
+ if (Triple.isOSFreeBSD()) {
+ // For FreeBSD, assume "soft" on all flavors of MIPS.
+ ABI = mips::FloatABI::Soft;
+ } else {
+ // 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.
+ ABI = mips::FloatABI::Hard;
+ }
}
assert(ABI != mips::FloatABI::Invalid && "must select an ABI");
@@ -267,7 +273,14 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
D.Diag(diag::warn_drv_unsupported_longcalls) << (ABICallsArg ? 0 : 1);
}
- mips::FloatABI FloatABI = mips::getMipsFloatABI(D, Args);
+ if (Arg *A = Args.getLastArg(options::OPT_mxgot, options::OPT_mno_xgot)) {
+ if (A->getOption().matches(options::OPT_mxgot))
+ Features.push_back("+xgot");
+ else
+ Features.push_back("-xgot");
+ }
+
+ mips::FloatABI FloatABI = mips::getMipsFloatABI(D, Args, Triple);
if (FloatABI == mips::FloatABI::Soft) {
// FIXME: Note, this is a hack. We need to pass the selected float
// mode to the MipsTargetInfoBase to define appropriate macros there.
diff --git a/lib/Driver/ToolChains/Arch/Mips.h b/lib/Driver/ToolChains/Arch/Mips.h
index 23e0cf79e154..074012f40fe5 100644
--- a/lib/Driver/ToolChains/Arch/Mips.h
+++ b/lib/Driver/ToolChains/Arch/Mips.h
@@ -38,7 +38,8 @@ void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args,
std::vector<StringRef> &Features);
StringRef getGnuCompatibleMipsABIName(StringRef ABI);
-mips::FloatABI getMipsFloatABI(const Driver &D, const llvm::opt::ArgList &Args);
+mips::FloatABI getMipsFloatABI(const Driver &D, const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
std::string getMipsABILibSuffix(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple);
bool hasMipsAbiArg(const llvm::opt::ArgList &Args, const char *Value);
diff --git a/lib/Driver/ToolChains/Arch/PPC.cpp b/lib/Driver/ToolChains/Arch/PPC.cpp
index 30f1a0d9022c..3e02e57e0f6c 100644
--- a/lib/Driver/ToolChains/Arch/PPC.cpp
+++ b/lib/Driver/ToolChains/Arch/PPC.cpp
@@ -13,6 +13,7 @@
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Host.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -115,7 +116,8 @@ ppc::ReadGOTPtrMode ppc::getPPCReadGOTPtrMode(const Driver &D, const llvm::Tripl
const ArgList &Args) {
if (Args.getLastArg(options::OPT_msecure_plt))
return ppc::ReadGOTPtrMode::SecurePlt;
- if (Triple.isOSNetBSD() || Triple.isOSOpenBSD() || Triple.isMusl())
+ if ((Triple.isOSFreeBSD() && Triple.getOSMajorVersion() >= 13) ||
+ Triple.isOSNetBSD() || Triple.isOSOpenBSD() || Triple.isMusl())
return ppc::ReadGOTPtrMode::SecurePlt;
else
return ppc::ReadGOTPtrMode::Bss;
diff --git a/lib/Driver/ToolChains/Arch/RISCV.cpp b/lib/Driver/ToolChains/Arch/RISCV.cpp
index b6768de4d299..624788a5874e 100644
--- a/lib/Driver/ToolChains/Arch/RISCV.cpp
+++ b/lib/Driver/ToolChains/Arch/RISCV.cpp
@@ -12,6 +12,7 @@
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/Support/TargetParser.h"
#include "llvm/Support/raw_ostream.h"
#include "ToolChains/CommonArgs.h"
@@ -189,168 +190,182 @@ static void getExtensionFeatures(const Driver &D,
}
}
-void riscv::getRISCVTargetFeatures(const Driver &D, const ArgList &Args,
- std::vector<StringRef> &Features) {
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- StringRef MArch = A->getValue();
+// Returns false if an error is diagnosed.
+static bool getArchFeatures(const Driver &D, StringRef MArch,
+ std::vector<StringRef> &Features,
+ const ArgList &Args) {
+ // RISC-V ISA strings must be lowercase.
+ if (llvm::any_of(MArch, [](char c) { return isupper(c); })) {
+ D.Diag(diag::err_drv_invalid_riscv_arch_name)
+ << MArch << "string must be lowercase";
+ return false;
+ }
- // RISC-V ISA strings must be lowercase.
- if (llvm::any_of(MArch, [](char c) { return isupper(c); })) {
- D.Diag(diag::err_drv_invalid_riscv_arch_name)
- << MArch << "string must be lowercase";
- return;
- }
+ // ISA string must begin with rv32 or rv64.
+ if (!(MArch.startswith("rv32") || MArch.startswith("rv64")) ||
+ (MArch.size() < 5)) {
+ D.Diag(diag::err_drv_invalid_riscv_arch_name)
+ << MArch << "string must begin with rv32{i,e,g} or rv64{i,g}";
+ return false;
+ }
- // ISA string must begin with rv32 or rv64.
- if (!(MArch.startswith("rv32") || MArch.startswith("rv64")) ||
- (MArch.size() < 5)) {
- D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch
- << "string must begin with rv32{i,e,g} or rv64{i,g}";
- return;
- }
+ bool HasRV64 = MArch.startswith("rv64");
+
+ // The canonical order specified in ISA manual.
+ // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
+ StringRef StdExts = "mafdqlcbjtpvn";
+ bool HasF = false, HasD = false;
+ char Baseline = MArch[4];
+
+ // First letter should be 'e', 'i' or 'g'.
+ switch (Baseline) {
+ default:
+ D.Diag(diag::err_drv_invalid_riscv_arch_name)
+ << MArch << "first letter should be 'e', 'i' or 'g'";
+ return false;
+ case 'e': {
+ StringRef Error;
+ // Currently LLVM does not support 'e'.
+ // Extension 'e' is not allowed in rv64.
+ if (HasRV64)
+ Error = "standard user-level extension 'e' requires 'rv32'";
+ else
+ Error = "unsupported standard user-level extension 'e'";
+ D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch << Error;
+ return false;
+ }
+ case 'i':
+ break;
+ case 'g':
+ // g = imafd
+ StdExts = StdExts.drop_front(4);
+ Features.push_back("+m");
+ Features.push_back("+a");
+ Features.push_back("+f");
+ Features.push_back("+d");
+ HasF = true;
+ HasD = true;
+ break;
+ }
- bool HasRV64 = MArch.startswith("rv64");
+ // Skip rvxxx
+ StringRef Exts = MArch.substr(5);
+
+ // Remove non-standard extensions and supervisor-level extensions.
+ // They have 'x', 's', 'sx' prefixes. Parse them at the end.
+ // Find the very first occurrence of 's' or 'x'.
+ StringRef OtherExts;
+ size_t Pos = Exts.find_first_of("sx");
+ if (Pos != StringRef::npos) {
+ OtherExts = Exts.substr(Pos);
+ Exts = Exts.substr(0, Pos);
+ }
- // The canonical order specified in ISA manual.
- // Ref: Table 22.1 in RISC-V User-Level ISA V2.2
- StringRef StdExts = "mafdqlcbjtpvn";
- bool HasF = false, HasD = false;
- char Baseline = MArch[4];
+ std::string Major, Minor;
+ if (!getExtensionVersion(D, MArch, std::string(1, Baseline), Exts, Major,
+ Minor))
+ return false;
- // First letter should be 'e', 'i' or 'g'.
- switch (Baseline) {
- default:
- D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch
- << "first letter should be 'e', 'i' or 'g'";
- return;
- case 'e': {
+ // TODO: Use version number when setting target features
+ // and consume the underscore '_' that might follow.
+
+ auto StdExtsItr = StdExts.begin();
+ auto StdExtsEnd = StdExts.end();
+
+ for (auto I = Exts.begin(), E = Exts.end(); I != E; ++I) {
+ char c = *I;
+
+ // Check ISA extensions are specified in the canonical order.
+ while (StdExtsItr != StdExtsEnd && *StdExtsItr != c)
+ ++StdExtsItr;
+
+ if (StdExtsItr == StdExtsEnd) {
+ // Either c contains a valid extension but it was not given in
+ // canonical order or it is an invalid extension.
StringRef Error;
- // Currently LLVM does not support 'e'.
- // Extension 'e' is not allowed in rv64.
- if (HasRV64)
- Error = "standard user-level extension 'e' requires 'rv32'";
+ if (StdExts.contains(c))
+ Error = "standard user-level extension not given in canonical order";
else
- Error = "unsupported standard user-level extension 'e'";
- D.Diag(diag::err_drv_invalid_riscv_arch_name)
- << MArch << Error;
- return;
+ Error = "invalid standard user-level extension";
+ D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
+ << MArch << Error << std::string(1, c);
+ return false;
}
- case 'i':
- break;
- case 'g':
- // g = imafd
- StdExts = StdExts.drop_front(4);
+
+ // Move to next char to prevent repeated letter.
+ ++StdExtsItr;
+
+ if (std::next(I) != E) {
+ // Skip c.
+ std::string Next = std::string(std::next(I), E);
+ std::string Major, Minor;
+ if (!getExtensionVersion(D, MArch, std::string(1, c), Next, Major, Minor))
+ return false;
+
+ // TODO: Use version number when setting target features
+ // and consume the underscore '_' that might follow.
+ }
+
+ // The order is OK, then push it into features.
+ switch (c) {
+ default:
+ // Currently LLVM supports only "mafdc".
+ D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
+ << MArch << "unsupported standard user-level extension"
+ << std::string(1, c);
+ return false;
+ case 'm':
Features.push_back("+m");
+ break;
+ case 'a':
Features.push_back("+a");
+ break;
+ case 'f':
Features.push_back("+f");
- Features.push_back("+d");
HasF = true;
+ break;
+ case 'd':
+ Features.push_back("+d");
HasD = true;
break;
+ case 'c':
+ Features.push_back("+c");
+ break;
}
+ }
- // Skip rvxxx
- StringRef Exts = MArch.substr(5);
-
- // Remove non-standard extensions and supervisor-level extensions.
- // They have 'x', 's', 'sx' prefixes. Parse them at the end.
- // Find the very first occurrence of 's' or 'x'.
- StringRef OtherExts;
- size_t Pos = Exts.find_first_of("sx");
- if (Pos != StringRef::npos) {
- OtherExts = Exts.substr(Pos);
- Exts = Exts.substr(0, Pos);
- }
-
- std::string Major, Minor;
- if (!getExtensionVersion(D, MArch, std::string(1, Baseline),
- Exts, Major, Minor))
- return;
-
- // TODO: Use version number when setting target features
- // and consume the underscore '_' that might follow.
-
- auto StdExtsItr = StdExts.begin();
- auto StdExtsEnd = StdExts.end();
-
- for (auto I = Exts.begin(), E = Exts.end(); I != E; ++I) {
- char c = *I;
-
- // Check ISA extensions are specified in the canonical order.
- while (StdExtsItr != StdExtsEnd && *StdExtsItr != c)
- ++StdExtsItr;
-
- if (StdExtsItr == StdExtsEnd) {
- // Either c contains a valid extension but it was not given in
- // canonical order or it is an invalid extension.
- StringRef Error;
- if (StdExts.contains(c))
- Error = "standard user-level extension not given in canonical order";
- else
- Error = "invalid standard user-level extension";
- D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
- << MArch << Error << std::string(1, c);
- return;
- }
-
- // Move to next char to prevent repeated letter.
- ++StdExtsItr;
+ // Dependency check.
+ // It's illegal to specify the 'd' (double-precision floating point)
+ // extension without also specifying the 'f' (single precision
+ // floating-point) extension.
+ if (HasD && !HasF) {
+ D.Diag(diag::err_drv_invalid_riscv_arch_name)
+ << MArch << "d requires f extension to also be specified";
+ return false;
+ }
- if (std::next(I) != E) {
- // Skip c.
- std::string Next = std::string(std::next(I), E);
- std::string Major, Minor;
- if (!getExtensionVersion(D, MArch, std::string(1, c),
- Next, Major, Minor))
- return;
-
- // TODO: Use version number when setting target features
- // and consume the underscore '_' that might follow.
- }
-
- // The order is OK, then push it into features.
- switch (c) {
- default:
- // Currently LLVM supports only "mafdc".
- D.Diag(diag::err_drv_invalid_riscv_ext_arch_name)
- << MArch << "unsupported standard user-level extension"
- << std::string(1, c);
- return;
- case 'm':
- Features.push_back("+m");
- break;
- case 'a':
- Features.push_back("+a");
- break;
- case 'f':
- Features.push_back("+f");
- HasF = true;
- break;
- case 'd':
- Features.push_back("+d");
- HasD = true;
- break;
- case 'c':
- Features.push_back("+c");
- break;
- }
- }
+ // Additional dependency checks.
+ // TODO: The 'q' extension requires rv64.
+ // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
- // Dependency check.
- // It's illegal to specify the 'd' (double-precision floating point)
- // extension without also specifying the 'f' (single precision
- // floating-point) extension.
- if (HasD && !HasF)
- D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch
- << "d requires f extension to also be specified";
+ // Handle all other types of extensions.
+ getExtensionFeatures(D, Args, Features, MArch, OtherExts);
- // Additional dependency checks.
- // TODO: The 'q' extension requires rv64.
- // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'.
+ return true;
+}
- // Handle all other types of extensions.
- getExtensionFeatures(D, Args, Features, MArch, OtherExts);
- }
+void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ llvm::Optional<StringRef> MArch;
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
+ MArch = A->getValue();
+ else if (Triple.getOS() == llvm::Triple::Linux)
+ // RISC-V Linux defaults to rv{32,64}gc.
+ MArch = Triple.getArch() == llvm::Triple::riscv32 ? "rv32gc" : "rv64gc";
+
+ if (MArch.hasValue() && !getArchFeatures(D, *MArch, Features, Args))
+ return;
// -mrelax is default, unless -mno-relax is specified.
if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true))
@@ -372,8 +387,16 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const ArgList &Args,
}
StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
- if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
+ assert((Triple.getArch() == llvm::Triple::riscv32 ||
+ Triple.getArch() == llvm::Triple::riscv64) &&
+ "Unexpected triple");
+
+ if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
return A->getValue();
- return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32" : "lp64";
+ // RISC-V Linux defaults to ilp32d/lp64d
+ if (Triple.getOS() == llvm::Triple::Linux)
+ return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32d" : "lp64d";
+ else
+ return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32" : "lp64";
}
diff --git a/lib/Driver/ToolChains/Arch/RISCV.h b/lib/Driver/ToolChains/Arch/RISCV.h
index 443526900aae..10eaf3c897b6 100644
--- a/lib/Driver/ToolChains/Arch/RISCV.h
+++ b/lib/Driver/ToolChains/Arch/RISCV.h
@@ -19,7 +19,8 @@ namespace clang {
namespace driver {
namespace tools {
namespace riscv {
-void getRISCVTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args,
+void getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
std::vector<llvm::StringRef> &Features);
StringRef getRISCVABI(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple);
diff --git a/lib/Driver/ToolChains/Arch/X86.cpp b/lib/Driver/ToolChains/Arch/X86.cpp
index 34be226b69e9..d2b97bf6ad71 100644
--- a/lib/Driver/ToolChains/Arch/X86.cpp
+++ b/lib/Driver/ToolChains/Arch/X86.cpp
@@ -13,6 +13,7 @@
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Host.h"
using namespace clang::driver;
using namespace clang::driver::tools;
diff --git a/lib/Driver/ToolChains/BareMetal.cpp b/lib/Driver/ToolChains/BareMetal.cpp
index 1544727050f4..dff0e04183ef 100644
--- a/lib/Driver/ToolChains/BareMetal.cpp
+++ b/lib/Driver/ToolChains/BareMetal.cpp
@@ -191,7 +191,7 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- C.addCommand(llvm::make_unique<Command>(JA, *this,
+ C.addCommand(std::make_unique<Command>(JA, *this,
Args.MakeArgString(TC.GetLinkerPath()),
CmdArgs, Inputs));
}
diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp
index cb861f27aeda..55d631733add 100644
--- a/lib/Driver/ToolChains/Clang.cpp
+++ b/lib/Driver/ToolChains/Clang.cpp
@@ -22,6 +22,7 @@
#include "InputInfo.h"
#include "PS4CPU.h"
#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Version.h"
@@ -301,95 +302,6 @@ static void ParseMPreferVectorWidth(const Driver &D, const ArgList &Args,
}
}
-static void getWebAssemblyTargetFeatures(const ArgList &Args,
- std::vector<StringRef> &Features) {
- handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group);
-}
-
-static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple,
- const ArgList &Args, ArgStringList &CmdArgs,
- bool ForAS) {
- const Driver &D = TC.getDriver();
- std::vector<StringRef> Features;
- switch (Triple.getArch()) {
- default:
- break;
- case llvm::Triple::mips:
- case llvm::Triple::mipsel:
- case llvm::Triple::mips64:
- case llvm::Triple::mips64el:
- mips::getMIPSTargetFeatures(D, Triple, Args, Features);
- break;
-
- case llvm::Triple::arm:
- case llvm::Triple::armeb:
- case llvm::Triple::thumb:
- case llvm::Triple::thumbeb:
- arm::getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS);
- break;
-
- case llvm::Triple::ppc:
- case llvm::Triple::ppc64:
- case llvm::Triple::ppc64le:
- ppc::getPPCTargetFeatures(D, Triple, Args, Features);
- break;
- case llvm::Triple::riscv32:
- case llvm::Triple::riscv64:
- riscv::getRISCVTargetFeatures(D, Args, Features);
- break;
- case llvm::Triple::systemz:
- systemz::getSystemZTargetFeatures(Args, Features);
- break;
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_be:
- aarch64::getAArch64TargetFeatures(D, Triple, Args, Features);
- break;
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- x86::getX86TargetFeatures(D, Triple, Args, Features);
- break;
- case llvm::Triple::hexagon:
- hexagon::getHexagonTargetFeatures(D, Args, Features);
- break;
- case llvm::Triple::wasm32:
- case llvm::Triple::wasm64:
- getWebAssemblyTargetFeatures(Args, Features);
- break;
- case llvm::Triple::sparc:
- case llvm::Triple::sparcel:
- case llvm::Triple::sparcv9:
- sparc::getSparcTargetFeatures(D, Args, Features);
- break;
- case llvm::Triple::r600:
- case llvm::Triple::amdgcn:
- amdgpu::getAMDGPUTargetFeatures(D, Args, Features);
- break;
- case llvm::Triple::msp430:
- msp430::getMSP430TargetFeatures(D, Args, Features);
- }
-
- // Find the last of each feature.
- llvm::StringMap<unsigned> LastOpt;
- for (unsigned I = 0, N = Features.size(); I < N; ++I) {
- StringRef Name = Features[I];
- assert(Name[0] == '-' || Name[0] == '+');
- LastOpt[Name.drop_front(1)] = I;
- }
-
- for (unsigned I = 0, N = Features.size(); I < N; ++I) {
- // If this feature was overridden, ignore it.
- StringRef Name = Features[I];
- llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name.drop_front(1));
- assert(LastI != LastOpt.end());
- unsigned Last = LastI->second;
- if (Last != I)
- continue;
-
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back(Name.data());
- }
-}
-
static bool
shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime,
const llvm::Triple &Triple) {
@@ -501,8 +413,6 @@ static codegenoptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) {
return codegenoptions::LimitedDebugInfo;
}
-enum class FramePointerKind { None, NonLeaf, All };
-
static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) {
switch (Triple.getArch()){
default:
@@ -579,22 +489,33 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args,
return true;
}
-static FramePointerKind getFramePointerKind(const ArgList &Args,
- const llvm::Triple &Triple) {
+static CodeGenOptions::FramePointerKind
+getFramePointerKind(const ArgList &Args, const llvm::Triple &Triple) {
+ // We have 4 states:
+ //
+ // 00) leaf retained, non-leaf retained
+ // 01) leaf retained, non-leaf omitted (this is invalid)
+ // 10) leaf omitted, non-leaf retained
+ // (what -momit-leaf-frame-pointer was designed for)
+ // 11) leaf omitted, non-leaf omitted
+ //
+ // "omit" options taking precedence over "no-omit" options is the only way
+ // to make 3 valid states representable
Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer,
options::OPT_fno_omit_frame_pointer);
bool OmitFP = A && A->getOption().matches(options::OPT_fomit_frame_pointer);
bool NoOmitFP =
A && A->getOption().matches(options::OPT_fno_omit_frame_pointer);
+ bool KeepLeaf =
+ Args.hasFlag(options::OPT_momit_leaf_frame_pointer,
+ options::OPT_mno_omit_leaf_frame_pointer, Triple.isPS4CPU());
if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) ||
(!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) {
- if (Args.hasFlag(options::OPT_momit_leaf_frame_pointer,
- options::OPT_mno_omit_leaf_frame_pointer,
- Triple.isPS4CPU()))
- return FramePointerKind::NonLeaf;
- return FramePointerKind::All;
+ if (KeepLeaf)
+ return CodeGenOptions::FramePointerKind::NonLeaf;
+ return CodeGenOptions::FramePointerKind::All;
}
- return FramePointerKind::None;
+ return CodeGenOptions::FramePointerKind::None;
}
/// Add a CC1 option to specify the debug compilation directory.
@@ -821,12 +742,14 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
}
}
- if (Args.hasArg(options::OPT_ftest_coverage) ||
- Args.hasArg(options::OPT_coverage))
+ bool EmitCovNotes = Args.hasArg(options::OPT_ftest_coverage) ||
+ Args.hasArg(options::OPT_coverage);
+ bool EmitCovData = Args.hasFlag(options::OPT_fprofile_arcs,
+ options::OPT_fno_profile_arcs, false) ||
+ Args.hasArg(options::OPT_coverage);
+ if (EmitCovNotes)
CmdArgs.push_back("-femit-coverage-notes");
- if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs,
- false) ||
- Args.hasArg(options::OPT_coverage))
+ if (EmitCovData)
CmdArgs.push_back("-femit-coverage-data");
if (Args.hasFlag(options::OPT_fcoverage_mapping,
@@ -862,35 +785,43 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-filter-files=" + v)));
}
- if (C.getArgs().hasArg(options::OPT_c) ||
- C.getArgs().hasArg(options::OPT_S)) {
- if (Output.isFilename()) {
- CmdArgs.push_back("-coverage-notes-file");
- SmallString<128> OutputFilename;
- if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
- OutputFilename = FinalOutput->getValue();
- else
- OutputFilename = llvm::sys::path::filename(Output.getBaseInput());
- SmallString<128> CoverageFilename = OutputFilename;
- if (llvm::sys::path::is_relative(CoverageFilename))
- (void)D.getVFS().makeAbsolute(CoverageFilename);
- llvm::sys::path::replace_extension(CoverageFilename, "gcno");
- CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
-
- // Leave -fprofile-dir= an unused argument unless .gcda emission is
- // enabled. To be polite, with '-fprofile-arcs -fno-profile-arcs' consider
- // the flag used. There is no -fno-profile-dir, so the user has no
- // targeted way to suppress the warning.
- if (Args.hasArg(options::OPT_fprofile_arcs) ||
- Args.hasArg(options::OPT_coverage)) {
- CmdArgs.push_back("-coverage-data-file");
- if (Arg *FProfileDir = Args.getLastArg(options::OPT_fprofile_dir)) {
- CoverageFilename = FProfileDir->getValue();
- llvm::sys::path::append(CoverageFilename, OutputFilename);
- }
- llvm::sys::path::replace_extension(CoverageFilename, "gcda");
- CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
+ // Leave -fprofile-dir= an unused argument unless .gcda emission is
+ // enabled. To be polite, with '-fprofile-arcs -fno-profile-arcs' consider
+ // the flag used. There is no -fno-profile-dir, so the user has no
+ // targeted way to suppress the warning.
+ Arg *FProfileDir = nullptr;
+ if (Args.hasArg(options::OPT_fprofile_arcs) ||
+ Args.hasArg(options::OPT_coverage))
+ FProfileDir = Args.getLastArg(options::OPT_fprofile_dir);
+
+ // Put the .gcno and .gcda files (if needed) next to the object file or
+ // bitcode file in the case of LTO.
+ // FIXME: There should be a simpler way to find the object file for this
+ // input, and this code probably does the wrong thing for commands that
+ // compile and link all at once.
+ if ((Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) &&
+ (EmitCovNotes || EmitCovData) && Output.isFilename()) {
+ SmallString<128> OutputFilename;
+ if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
+ OutputFilename = FinalOutput->getValue();
+ else
+ OutputFilename = llvm::sys::path::filename(Output.getBaseInput());
+ SmallString<128> CoverageFilename = OutputFilename;
+ if (llvm::sys::path::is_relative(CoverageFilename))
+ (void)D.getVFS().makeAbsolute(CoverageFilename);
+ llvm::sys::path::replace_extension(CoverageFilename, "gcno");
+
+ CmdArgs.push_back("-coverage-notes-file");
+ CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
+
+ if (EmitCovData) {
+ if (FProfileDir) {
+ CoverageFilename = FProfileDir->getValue();
+ llvm::sys::path::append(CoverageFilename, OutputFilename);
}
+ llvm::sys::path::replace_extension(CoverageFilename, "gcda");
+ CmdArgs.push_back("-coverage-data-file");
+ CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
}
}
}
@@ -1045,7 +976,6 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
ArgStringList &CmdArgs,
const InputInfo &Output,
const InputInfoList &Inputs) const {
- Arg *A;
const bool IsIAMCU = getToolChain().getTriple().isOSIAMCU();
CheckPreprocessingOptions(D, Args);
@@ -1054,9 +984,20 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_CC);
// Handle dependency file generation.
- if ((A = Args.getLastArg(options::OPT_M, options::OPT_MM)) ||
- (A = Args.getLastArg(options::OPT_MD)) ||
- (A = Args.getLastArg(options::OPT_MMD))) {
+ Arg *ArgM = Args.getLastArg(options::OPT_MM);
+ if (!ArgM)
+ ArgM = Args.getLastArg(options::OPT_M);
+ Arg *ArgMD = Args.getLastArg(options::OPT_MMD);
+ if (!ArgMD)
+ ArgMD = Args.getLastArg(options::OPT_MD);
+
+ // -M and -MM imply -w.
+ if (ArgM)
+ CmdArgs.push_back("-w");
+ else
+ ArgM = ArgMD;
+
+ if (ArgM) {
// Determine the output location.
const char *DepFile;
if (Arg *MF = Args.getLastArg(options::OPT_MF)) {
@@ -1064,8 +1005,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
C.addFailureResultFile(DepFile, &JA);
} else if (Output.getType() == types::TY_Dependencies) {
DepFile = Output.getFilename();
- } else if (A->getOption().matches(options::OPT_M) ||
- A->getOption().matches(options::OPT_MM)) {
+ } else if (!ArgMD) {
DepFile = "-";
} else {
DepFile = getDependencyFileName(Args, Inputs);
@@ -1074,8 +1014,22 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-dependency-file");
CmdArgs.push_back(DepFile);
+ bool HasTarget = false;
+ for (const Arg *A : Args.filtered(options::OPT_MT, options::OPT_MQ)) {
+ HasTarget = true;
+ A->claim();
+ if (A->getOption().matches(options::OPT_MT)) {
+ A->render(Args, CmdArgs);
+ } else {
+ CmdArgs.push_back("-MT");
+ SmallString<128> Quoted;
+ QuoteTarget(A->getValue(), Quoted);
+ CmdArgs.push_back(Args.MakeArgString(Quoted));
+ }
+ }
+
// Add a default target if one wasn't specified.
- if (!Args.hasArg(options::OPT_MT) && !Args.hasArg(options::OPT_MQ)) {
+ if (!HasTarget) {
const char *DepTarget;
// If user provided -o, that is the dependency target, except
@@ -1092,17 +1046,14 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
DepTarget = Args.MakeArgString(llvm::sys::path::filename(P));
}
- if (!A->getOption().matches(options::OPT_MD) && !A->getOption().matches(options::OPT_MMD)) {
- CmdArgs.push_back("-w");
- }
CmdArgs.push_back("-MT");
SmallString<128> Quoted;
QuoteTarget(DepTarget, Quoted);
CmdArgs.push_back(Args.MakeArgString(Quoted));
}
- if (A->getOption().matches(options::OPT_M) ||
- A->getOption().matches(options::OPT_MD))
+ if (ArgM->getOption().matches(options::OPT_M) ||
+ ArgM->getOption().matches(options::OPT_MD))
CmdArgs.push_back("-sys-header-deps");
if ((isa<PrecompileJobAction>(JA) &&
!Args.hasArg(options::OPT_fno_module_file_deps)) ||
@@ -1111,8 +1062,8 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
}
if (Args.hasArg(options::OPT_MG)) {
- if (!A || A->getOption().matches(options::OPT_MD) ||
- A->getOption().matches(options::OPT_MMD))
+ if (!ArgM || ArgM->getOption().matches(options::OPT_MD) ||
+ ArgM->getOption().matches(options::OPT_MMD))
D.Diag(diag::err_drv_mg_requires_m_or_mm);
CmdArgs.push_back("-MG");
}
@@ -1120,22 +1071,6 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_MP);
Args.AddLastArg(CmdArgs, options::OPT_MV);
- // Convert all -MQ <target> args to -MT <quoted target>
- for (const Arg *A : Args.filtered(options::OPT_MT, options::OPT_MQ)) {
- A->claim();
-
- if (A->getOption().matches(options::OPT_MQ)) {
- CmdArgs.push_back("-MT");
- SmallString<128> Quoted;
- QuoteTarget(A->getValue(), Quoted);
- CmdArgs.push_back(Args.MakeArgString(Quoted));
-
- // -MT flag - no change
- } else {
- A->render(Args, CmdArgs);
- }
- }
-
// Add offload include arguments specific for CUDA. This must happen before
// we -I or -include anything else, because we must pick up the CUDA headers
// from the particular CUDA installation, rather than from e.g.
@@ -1236,6 +1171,9 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
// Do not claim the argument so that the use of the argument does not
// silently go unnoticed on toolchains which do not honour the option.
continue;
+ } else if (A->getOption().matches(options::OPT_stdlibxx_isystem)) {
+ // Translated to -internal-isystem by the driver, no need to pass to cc1.
+ continue;
}
// Not translated, render as usual.
@@ -1290,11 +1228,15 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
// of an offloading programming model.
// Add C++ include arguments, if needed.
- if (types::isCXX(Inputs[0].getType()))
- forAllAssociatedToolChains(C, JA, getToolChain(),
- [&Args, &CmdArgs](const ToolChain &TC) {
- TC.AddClangCXXStdlibIncludeArgs(Args, CmdArgs);
- });
+ if (types::isCXX(Inputs[0].getType())) {
+ bool HasStdlibxxIsystem = Args.hasArg(options::OPT_stdlibxx_isystem);
+ forAllAssociatedToolChains(
+ C, JA, getToolChain(),
+ [&Args, &CmdArgs, HasStdlibxxIsystem](const ToolChain &TC) {
+ HasStdlibxxIsystem ? TC.AddClangCXXStdlibIsystemArgs(Args, CmdArgs)
+ : TC.AddClangCXXStdlibIncludeArgs(Args, CmdArgs);
+ });
+ }
// Add system include arguments for all targets but IAMCU.
if (!IsIAMCU)
@@ -1635,7 +1577,7 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName.data());
- mips::FloatABI ABI = mips::getMipsFloatABI(D, Args);
+ mips::FloatABI ABI = mips::getMipsFloatABI(D, Args, Triple);
if (ABI == mips::FloatABI::Soft) {
// Floating point operations and argument passing are soft.
CmdArgs.push_back("-msoft-float");
@@ -1648,13 +1590,6 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
CmdArgs.push_back("hard");
}
- if (Arg *A = Args.getLastArg(options::OPT_mxgot, options::OPT_mno_xgot)) {
- if (A->getOption().matches(options::OPT_mxgot)) {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-mxgot");
- }
- }
-
if (Arg *A = Args.getLastArg(options::OPT_mldc1_sdc1,
options::OPT_mno_ldc1_sdc1)) {
if (A->getOption().matches(options::OPT_mno_ldc1_sdc1)) {
@@ -1842,21 +1777,11 @@ void Clang::AddPPCTargetArgs(const ArgList &Args,
void Clang::AddRISCVTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- // FIXME: currently defaults to the soft-float ABIs. Will need to be
- // expanded to select ilp32f, ilp32d, lp64f, lp64d when appropriate.
- const char *ABIName = nullptr;
const llvm::Triple &Triple = getToolChain().getTriple();
- if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ))
- ABIName = A->getValue();
- else if (Triple.getArch() == llvm::Triple::riscv32)
- ABIName = "ilp32";
- else if (Triple.getArch() == llvm::Triple::riscv64)
- ABIName = "lp64";
- else
- llvm_unreachable("Unexpected triple!");
+ StringRef ABIName = riscv::getRISCVABI(Args, Triple);
CmdArgs.push_back("-target-abi");
- CmdArgs.push_back(ABIName);
+ CmdArgs.push_back(ABIName.data());
}
void Clang::AddSparcTargetArgs(const ArgList &Args,
@@ -1996,7 +1921,8 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename,
if (!CompilationDatabase) {
std::error_code EC;
- auto File = llvm::make_unique<llvm::raw_fd_ostream>(Filename, EC, llvm::sys::fs::F_Text);
+ auto File = std::make_unique<llvm::raw_fd_ostream>(Filename, EC,
+ llvm::sys::fs::OF_Text);
if (EC) {
D.Diag(clang::diag::err_drv_compilationdatabase) << Filename
<< EC.message();
@@ -2005,13 +1931,14 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename,
CompilationDatabase = std::move(File);
}
auto &CDB = *CompilationDatabase;
- SmallString<128> Buf;
- if (llvm::sys::fs::current_path(Buf))
- Buf = ".";
- CDB << "{ \"directory\": \"" << escape(Buf) << "\"";
+ auto CWD = D.getVFS().getCurrentWorkingDirectory();
+ if (!CWD)
+ CWD = ".";
+ CDB << "{ \"directory\": \"" << escape(*CWD) << "\"";
CDB << ", \"file\": \"" << escape(Input.getFilename()) << "\"";
CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\"";
CDB << ", \"arguments\": [\"" << escape(D.ClangExecutable) << "\"";
+ SmallString<128> Buf;
Buf = "-x";
Buf += types::getTypeName(Input.getType());
CDB << ", \"" << escape(Buf) << "\"";
@@ -2029,6 +1956,8 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename,
// Skip writing dependency output and the compilation database itself.
if (O.getGroup().isValid() && O.getGroup().getID() == options::OPT_M_Group)
continue;
+ if (O.getID() == options::OPT_gen_cdb_fragment_path)
+ continue;
// Skip inputs.
if (O.getKind() == Option::InputClass)
continue;
@@ -2043,6 +1972,40 @@ void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename,
CDB << ", \"" << escape(Buf) << "\"]},\n";
}
+void Clang::DumpCompilationDatabaseFragmentToDir(
+ StringRef Dir, Compilation &C, StringRef Target, const InputInfo &Output,
+ const InputInfo &Input, const llvm::opt::ArgList &Args) const {
+ // If this is a dry run, do not create the compilation database file.
+ if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH))
+ return;
+
+ if (CompilationDatabase)
+ DumpCompilationDatabase(C, "", Target, Output, Input, Args);
+
+ SmallString<256> Path = Dir;
+ const auto &Driver = C.getDriver();
+ Driver.getVFS().makeAbsolute(Path);
+ auto Err = llvm::sys::fs::create_directory(Path, /*IgnoreExisting=*/true);
+ if (Err) {
+ Driver.Diag(diag::err_drv_compilationdatabase) << Dir << Err.message();
+ return;
+ }
+
+ llvm::sys::path::append(
+ Path,
+ Twine(llvm::sys::path::filename(Input.getFilename())) + ".%%%%.json");
+ int FD;
+ SmallString<256> TempPath;
+ Err = llvm::sys::fs::createUniqueFile(Path, FD, TempPath);
+ if (Err) {
+ Driver.Diag(diag::err_drv_compilationdatabase) << Path << Err.message();
+ return;
+ }
+ CompilationDatabase =
+ std::make_unique<llvm::raw_fd_ostream>(FD, /*shouldClose=*/true);
+ DumpCompilationDatabase(C, "", Target, Output, Input, Args);
+}
+
static void CollectArgsForIntegratedAssembler(Compilation &C,
const ArgList &Args,
ArgStringList &CmdArgs,
@@ -2080,6 +2043,9 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
break;
}
+ // If you add more args here, also add them to the block below that
+ // starts with "// If CollectArgsForIntegratedAssembler() isn't called below".
+
// When passing -I arguments to the assembler we sometimes need to
// unconditionally take the next argument. For example, when parsing
// '-Wa,-I -Wa,foo' we need to accept the -Wa,foo arg after seeing the
@@ -2169,6 +2135,8 @@ static void CollectArgsForIntegratedAssembler(Compilation &C,
CmdArgs.push_back("-msave-temp-labels");
} else if (Value == "--fatal-warnings") {
CmdArgs.push_back("-massembler-fatal-warnings");
+ } else if (Value == "--no-warn" || Value == "-W") {
+ CmdArgs.push_back("-massembler-no-warn");
} else if (Value == "--noexecstack") {
UseNoExecStack = true;
} else if (Value.startswith("-compress-debug-sections") ||
@@ -2804,6 +2772,10 @@ static void RenderModulesOptions(Compilation &C, const Driver &D,
std::string("-fprebuilt-module-path=") + A->getValue()));
A->claim();
}
+ if (Args.hasFlag(options::OPT_fmodules_validate_input_files_content,
+ options::OPT_fno_modules_validate_input_files_content,
+ false))
+ CmdArgs.push_back("-fvalidate-ast-input-files-content");
}
// -fmodule-name specifies the module that is currently being built (or
@@ -3342,7 +3314,6 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D,
Args.getLastArg(options::OPT_ggnu_pubnames, options::OPT_gno_gnu_pubnames,
options::OPT_gpubnames, options::OPT_gno_pubnames);
if (DwarfFission != DwarfFissionKind::None ||
- DebuggerTuning == llvm::DebuggerKind::LLDB ||
(PubnamesArg && checkDebugInfoOption(PubnamesArg, Args, D, TC)))
if (!PubnamesArg ||
(!PubnamesArg->getOption().matches(options::OPT_gno_gnu_pubnames) &&
@@ -3482,6 +3453,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (const Arg *MJ = Args.getLastArg(options::OPT_MJ)) {
DumpCompilationDatabase(C, MJ->getValue(), TripleStr, Output, Input, Args);
Args.ClaimAllArgs(options::OPT_MJ);
+ } else if (const Arg *GenCDBFragment =
+ Args.getLastArg(options::OPT_gen_cdb_fragment_path)) {
+ DumpCompilationDatabaseFragmentToDir(GenCDBFragment->getValue(), C,
+ TripleStr, Output, Input, Args);
+ Args.ClaimAllArgs(options::OPT_gen_cdb_fragment_path);
}
if (IsCuda || IsHIP) {
@@ -3544,6 +3520,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Select the appropriate action.
RewriteKind rewriteKind = RK_None;
+ // If CollectArgsForIntegratedAssembler() isn't called below, claim the args
+ // it claims when not running an assembler. Otherwise, clang would emit
+ // "argument unused" warnings for assembler flags when e.g. adding "-E" to
+ // flags while debugging something. That'd be somewhat inconvenient, and it's
+ // also inconsistent with most other flags -- we don't warn on
+ // -ffunction-sections not being used in -E mode either for example, even
+ // though it's not really used either.
+ if (!isa<AssembleJobAction>(JA)) {
+ // The args claimed here should match the args used in
+ // CollectArgsForIntegratedAssembler().
+ if (TC.useIntegratedAs()) {
+ Args.ClaimAllArgs(options::OPT_mrelax_all);
+ Args.ClaimAllArgs(options::OPT_mno_relax_all);
+ Args.ClaimAllArgs(options::OPT_mincremental_linker_compatible);
+ Args.ClaimAllArgs(options::OPT_mno_incremental_linker_compatible);
+ switch (C.getDefaultToolChain().getArch()) {
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ Args.ClaimAllArgs(options::OPT_mimplicit_it_EQ);
+ break;
+ default:
+ break;
+ }
+ }
+ Args.ClaimAllArgs(options::OPT_Wa_COMMA);
+ Args.ClaimAllArgs(options::OPT_Xassembler);
+ }
+
if (isa<AnalyzeJobAction>(JA)) {
assert(JA.getType() == types::TY_Plist && "Invalid output type.");
CmdArgs.push_back("-analyze");
@@ -3587,25 +3593,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
} else if (JA.getType() == types::TY_LLVM_BC ||
JA.getType() == types::TY_LTO_BC) {
CmdArgs.push_back("-emit-llvm-bc");
- } else if (JA.getType() == types::TY_IFS) {
- StringRef StubFormat =
- llvm::StringSwitch<StringRef>(
- Args.hasArg(options::OPT_iterface_stub_version_EQ)
- ? Args.getLastArgValue(options::OPT_iterface_stub_version_EQ)
- : "")
- .Case("experimental-yaml-elf-v1", "experimental-yaml-elf-v1")
- .Case("experimental-tapi-elf-v1", "experimental-tapi-elf-v1")
- .Default("");
-
- if (StubFormat.empty())
- D.Diag(diag::err_drv_invalid_value)
- << "Must specify a valid interface stub format type using "
- << "-interface-stub-version=<experimental-tapi-elf-v1 | "
- "experimental-yaml-elf-v1>";
-
+ } else if (JA.getType() == types::TY_IFS ||
+ JA.getType() == types::TY_IFS_CPP) {
+ StringRef ArgStr =
+ Args.hasArg(options::OPT_interface_stub_version_EQ)
+ ? Args.getLastArgValue(options::OPT_interface_stub_version_EQ)
+ : "experimental-ifs-v1";
CmdArgs.push_back("-emit-interface-stubs");
CmdArgs.push_back(
- Args.MakeArgString(Twine("-interface-stub-version=") + StubFormat));
+ Args.MakeArgString(Twine("-interface-stub-version=") + ArgStr.str()));
} else if (JA.getType() == types::TY_PP_Asm) {
CmdArgs.push_back("-S");
} else if (JA.getType() == types::TY_AST) {
@@ -3635,13 +3631,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (D.isUsingLTO() && !isDeviceOffloadAction) {
Args.AddLastArg(CmdArgs, options::OPT_flto, options::OPT_flto_EQ);
-
- // The Darwin and PS4 linkers currently use the legacy LTO API, which
- // does not support LTO unit features (CFI, whole program vtable opt)
- // under ThinLTO.
- if (!(RawTriple.isOSDarwin() || RawTriple.isPS4()) ||
- D.getLTOMode() == LTOK_Full)
- CmdArgs.push_back("-flto-unit");
+ CmdArgs.push_back("-flto-unit");
}
}
@@ -3761,7 +3751,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
II.getInputArg().renderAsInput(Args, CmdArgs);
}
- C.addCommand(llvm::make_unique<Command>(JA, *this, D.getClangProgramPath(),
+ C.addCommand(std::make_unique<Command>(JA, *this, D.getClangProgramPath(),
CmdArgs, Inputs));
return;
}
@@ -3806,6 +3796,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (isa<AnalyzeJobAction>(JA))
RenderAnalyzerOptions(Args, CmdArgs, Triple, Input);
+ if (isa<AnalyzeJobAction>(JA) ||
+ (isa<PreprocessJobAction>(JA) && Args.hasArg(options::OPT__analyze)))
+ CmdArgs.push_back("-setup-static-analyzer");
+
// Enable compatilibily mode to avoid analyzer-config related errors.
// Since we can't access frontend flags through hasArg, let's manually iterate
// through them.
@@ -3946,12 +3940,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false))
CmdArgs.push_back("-fdefault-calling-conv=stdcall");
- FramePointerKind FPKeepKind = getFramePointerKind(Args, RawTriple);
- if (FPKeepKind != FramePointerKind::None) {
- CmdArgs.push_back("-mdisable-fp-elim");
- if (FPKeepKind == FramePointerKind::NonLeaf)
- CmdArgs.push_back("-momit-leaf-frame-pointer");
+ CodeGenOptions::FramePointerKind FPKeepKind =
+ getFramePointerKind(Args, RawTriple);
+ const char *FPKeepKindStr = nullptr;
+ switch (FPKeepKind) {
+ case CodeGenOptions::FramePointerKind::None:
+ FPKeepKindStr = "-mframe-pointer=none";
+ break;
+ case CodeGenOptions::FramePointerKind::NonLeaf:
+ FPKeepKindStr = "-mframe-pointer=non-leaf";
+ break;
+ case CodeGenOptions::FramePointerKind::All:
+ FPKeepKindStr = "-mframe-pointer=all";
+ break;
}
+ assert(FPKeepKindStr && "unknown FramePointerKind");
+ CmdArgs.push_back(FPKeepKindStr);
+
if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss,
options::OPT_fno_zero_initialized_in_bss))
CmdArgs.push_back("-mno-zero-initialized-in-bss");
@@ -4003,11 +4008,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
RenderFloatingPointOptions(TC, D, OFastEnabled, Args, CmdArgs);
- if (Arg *A = Args.getLastArg(options::OPT_mlong_double_64,
- options::OPT_mlong_double_128)) {
+ if (Arg *A = Args.getLastArg(options::OPT_LongDouble_Group)) {
if (TC.getArch() == llvm::Triple::x86 ||
- TC.getArch() == llvm::Triple::x86_64 ||
- TC.getArch() == llvm::Triple::ppc || TC.getTriple().isPPC64())
+ TC.getArch() == llvm::Triple::x86_64)
+ A->render(Args, CmdArgs);
+ else if ((TC.getArch() == llvm::Triple::ppc || TC.getTriple().isPPC64()) &&
+ (A->getOption().getID() != options::OPT_mlong_double_80))
A->render(Args, CmdArgs);
else
D.Diag(diag::err_drv_unsupported_opt_for_target)
@@ -4018,8 +4024,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// toolchains which have the integrated assembler on by default.
bool IsIntegratedAssemblerDefault = TC.IsIntegratedAssemblerDefault();
if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm,
- IsIntegratedAssemblerDefault) ||
- Args.hasArg(options::OPT_dA))
+ IsIntegratedAssemblerDefault))
CmdArgs.push_back("-masm-verbose");
if (!TC.useIntegratedAs())
@@ -4386,6 +4391,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue());
}
+ if (Args.hasArg(options::OPT_fexperimental_new_constant_interpreter))
+ CmdArgs.push_back("-fexperimental-new-constant-interpreter");
+
+ if (Args.hasArg(options::OPT_fforce_experimental_new_constant_interpreter))
+ CmdArgs.push_back("-fforce-experimental-new-constant-interpreter");
+
if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) {
CmdArgs.push_back("-fbracket-depth");
CmdArgs.push_back(A->getValue());
@@ -4571,20 +4582,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (TC.SupportsProfiling())
Args.AddLastArg(CmdArgs, options::OPT_mfentry);
- // -flax-vector-conversions is default.
- if (!Args.hasFlag(options::OPT_flax_vector_conversions,
- options::OPT_fno_lax_vector_conversions))
- CmdArgs.push_back("-fno-lax-vector-conversions");
-
if (Args.getLastArg(options::OPT_fapple_kext) ||
(Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType)))
CmdArgs.push_back("-fapple-kext");
+ Args.AddLastArg(CmdArgs, options::OPT_flax_vector_conversions_EQ);
Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
Args.AddLastArg(CmdArgs, options::OPT_ftime_trace);
+ Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ);
Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
Args.AddLastArg(CmdArgs, options::OPT_malign_double);
@@ -4667,6 +4675,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Forward -cl options to -cc1
RenderOpenCLOptions(Args, CmdArgs);
+ if (Args.hasFlag(options::OPT_fhip_new_launch_api,
+ options::OPT_fno_hip_new_launch_api, false))
+ CmdArgs.push_back("-fhip-new-launch-api");
+
if (Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) {
CmdArgs.push_back(
Args.MakeArgString(Twine("-fcf-protection=") + A->getValue()));
@@ -4771,13 +4783,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fuse-line-directives");
// -fms-compatibility=0 is default.
- if (Args.hasFlag(options::OPT_fms_compatibility,
- options::OPT_fno_ms_compatibility,
- (IsWindowsMSVC &&
- Args.hasFlag(options::OPT_fms_extensions,
- options::OPT_fno_ms_extensions, true))))
+ bool IsMSVCCompat = Args.hasFlag(
+ options::OPT_fms_compatibility, options::OPT_fno_ms_compatibility,
+ (IsWindowsMSVC && Args.hasFlag(options::OPT_fms_extensions,
+ options::OPT_fno_ms_extensions, true)));
+ if (IsMSVCCompat)
CmdArgs.push_back("-fms-compatibility");
+ // Handle -fgcc-version, if present.
+ VersionTuple GNUCVer;
+ if (Arg *A = Args.getLastArg(options::OPT_fgnuc_version_EQ)) {
+ // Check that the version has 1 to 3 components and the minor and patch
+ // versions fit in two decimal digits.
+ StringRef Val = A->getValue();
+ Val = Val.empty() ? "0" : Val; // Treat "" as 0 or disable.
+ bool Invalid = GNUCVer.tryParse(Val);
+ unsigned Minor = GNUCVer.getMinor().getValueOr(0);
+ unsigned Patch = GNUCVer.getSubminor().getValueOr(0);
+ if (Invalid || GNUCVer.getBuild() || Minor >= 100 || Patch >= 100) {
+ D.Diag(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue();
+ }
+ } else if (!IsMSVCCompat) {
+ // Imitate GCC 4.2.1 by default if -fms-compatibility is not in effect.
+ GNUCVer = VersionTuple(4, 2, 1);
+ }
+ if (!GNUCVer.empty()) {
+ CmdArgs.push_back(
+ Args.MakeArgString("-fgnuc-version=" + GNUCVer.getAsString()));
+ }
+
VersionTuple MSVT = TC.computeMSVCVersion(&D, Args);
if (!MSVT.empty())
CmdArgs.push_back(
@@ -4857,6 +4892,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Std && (Std->containsValue("c++2a") || Std->containsValue("c++latest"));
RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules);
+ if (Args.hasFlag(options::OPT_fpch_validate_input_files_content,
+ options::OPT_fno_pch_validate_input_files_content, false))
+ CmdArgs.push_back("-fvalidate-ast-input-files-content");
+
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_new_pass_manager,
options::OPT_fno_experimental_new_pass_manager);
@@ -4873,9 +4912,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
addExceptionArgs(Args, InputType, TC, KernelOrKext, Runtime, CmdArgs);
// Handle exception personalities
- Arg *A = Args.getLastArg(options::OPT_fsjlj_exceptions,
- options::OPT_fseh_exceptions,
- options::OPT_fdwarf_exceptions);
+ Arg *A = Args.getLastArg(
+ options::OPT_fsjlj_exceptions, options::OPT_fseh_exceptions,
+ options::OPT_fdwarf_exceptions, options::OPT_fwasm_exceptions);
if (A) {
const Option &Opt = A->getOption();
if (Opt.matches(options::OPT_fsjlj_exceptions))
@@ -4884,6 +4923,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fseh-exceptions");
if (Opt.matches(options::OPT_fdwarf_exceptions))
CmdArgs.push_back("-fdwarf-exceptions");
+ if (Opt.matches(options::OPT_fwasm_exceptions))
+ CmdArgs.push_back("-fwasm-exceptions");
} else {
switch (TC.GetExceptionModel(Args)) {
default:
@@ -5322,9 +5363,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(TargetInfo.str()));
}
- bool WholeProgramVTables =
- Args.hasFlag(options::OPT_fwhole_program_vtables,
- options::OPT_fno_whole_program_vtables, false);
+ bool VirtualFunctionElimination =
+ Args.hasFlag(options::OPT_fvirtual_function_elimination,
+ options::OPT_fno_virtual_function_elimination, false);
+ if (VirtualFunctionElimination) {
+ // VFE requires full LTO (currently, this might be relaxed to allow ThinLTO
+ // in the future).
+ if (D.getLTOMode() != LTOK_Full)
+ D.Diag(diag::err_drv_argument_only_allowed_with)
+ << "-fvirtual-function-elimination"
+ << "-flto=full";
+
+ CmdArgs.push_back("-fvirtual-function-elimination");
+ }
+
+ // VFE requires whole-program-vtables, and enables it by default.
+ bool WholeProgramVTables = Args.hasFlag(
+ options::OPT_fwhole_program_vtables,
+ options::OPT_fno_whole_program_vtables, VirtualFunctionElimination);
+ if (VirtualFunctionElimination && !WholeProgramVTables) {
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fno-whole-program-vtables"
+ << "-fvirtual-function-elimination";
+ }
+
if (WholeProgramVTables) {
if (!D.isUsingLTO())
D.Diag(diag::err_drv_argument_only_allowed_with)
@@ -5333,14 +5395,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fwhole-program-vtables");
}
- bool RequiresSplitLTOUnit = WholeProgramVTables || Sanitize.needsLTO();
+ bool DefaultsSplitLTOUnit = WholeProgramVTables || Sanitize.needsLTO();
bool SplitLTOUnit =
Args.hasFlag(options::OPT_fsplit_lto_unit,
- options::OPT_fno_split_lto_unit, RequiresSplitLTOUnit);
- if (RequiresSplitLTOUnit && !SplitLTOUnit)
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << "-fno-split-lto-unit"
- << (WholeProgramVTables ? "-fwhole-program-vtables" : "-fsanitize=cfi");
+ options::OPT_fno_split_lto_unit, DefaultsSplitLTOUnit);
+ if (Sanitize.needsLTO() && !SplitLTOUnit)
+ D.Diag(diag::err_drv_argument_not_allowed_with) << "-fno-split-lto-unit"
+ << "-fsanitize=cfi";
if (SplitLTOUnit)
CmdArgs.push_back("-fsplit-lto-unit");
@@ -5469,16 +5530,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
(InputType == types::TY_C || InputType == types::TY_CXX)) {
auto CLCommand =
getCLFallback()->GetCommand(C, JA, Output, Inputs, Args, LinkingOutput);
- C.addCommand(llvm::make_unique<FallbackCommand>(
+ C.addCommand(std::make_unique<FallbackCommand>(
JA, *this, Exec, CmdArgs, Inputs, std::move(CLCommand)));
} else if (Args.hasArg(options::OPT__SLASH_fallback) &&
isa<PrecompileJobAction>(JA)) {
// In /fallback builds, run the main compilation even if the pch generation
// fails, so that the main compilation's fallback to cl.exe runs.
- C.addCommand(llvm::make_unique<ForceSuccessCommand>(JA, *this, Exec,
+ C.addCommand(std::make_unique<ForceSuccessCommand>(JA, *this, Exec,
CmdArgs, Inputs));
} else {
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
// Make the compile command echo its inputs for /showFilenames.
@@ -5489,7 +5550,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
if (Arg *A = Args.getLastArg(options::OPT_pg))
- if (FPKeepKind == FramePointerKind::None)
+ if (FPKeepKind == CodeGenOptions::FramePointerKind::None)
D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer"
<< A->getAsString(Args);
@@ -5954,15 +6015,14 @@ const char *Clang::getBaseInputStem(const ArgList &Args,
const char *Clang::getDependencyFileName(const ArgList &Args,
const InputInfoList &Inputs) {
// FIXME: Think about this more.
- std::string Res;
if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
- std::string Str(OutputOpt->getValue());
- Res = Str.substr(0, Str.rfind('.'));
- } else {
- Res = getBaseInputStem(Args, Inputs);
+ SmallString<128> OutputFilename(OutputOpt->getValue());
+ llvm::sys::path::replace_extension(OutputFilename, llvm::Twine('d'));
+ return Args.MakeArgString(OutputFilename);
}
- return Args.MakeArgString(Res + ".d");
+
+ return Args.MakeArgString(Twine(getBaseInputStem(Args, Inputs)) + ".d");
}
// Begin ClangAs
@@ -6205,7 +6265,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Input.getFilename());
const char *Exec = getToolChain().getDriver().getClangProgramPath();
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
// Begin OffloadBundler
@@ -6288,7 +6348,7 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(TCArgs.MakeArgString(UB));
// All the inputs are encoded as commands.
- C.addCommand(llvm::make_unique<Command>(
+ C.addCommand(std::make_unique<Command>(
JA, *this,
TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())),
CmdArgs, None));
@@ -6354,8 +6414,38 @@ void OffloadBundler::ConstructJobMultipleOutputs(
CmdArgs.push_back("-unbundle");
// All the inputs are encoded as commands.
- C.addCommand(llvm::make_unique<Command>(
+ C.addCommand(std::make_unique<Command>(
JA, *this,
TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())),
CmdArgs, None));
}
+
+void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+
+ const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
+
+ // Add the "effective" target triple.
+ CmdArgs.push_back("-target");
+ CmdArgs.push_back(Args.MakeArgString(Triple.getTriple()));
+
+ // Add the output file name.
+ assert(Output.isFilename() && "Invalid output.");
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ // Add inputs.
+ for (const InputInfo &I : Inputs) {
+ assert(I.isFilename() && "Invalid input.");
+ CmdArgs.push_back(I.getFilename());
+ }
+
+ C.addCommand(std::make_unique<Command>(
+ JA, *this,
+ Args.MakeArgString(getToolChain().GetProgramPath(getShortName())),
+ CmdArgs, Inputs));
+}
diff --git a/lib/Driver/ToolChains/Clang.h b/lib/Driver/ToolChains/Clang.h
index fc4f5ecdd28a..b345c02489d4 100644
--- a/lib/Driver/ToolChains/Clang.h
+++ b/lib/Driver/ToolChains/Clang.h
@@ -95,6 +95,10 @@ private:
const InputInfo &Output, const InputInfo &Input,
const llvm::opt::ArgList &Args) const;
+ void DumpCompilationDatabaseFragmentToDir(
+ StringRef Dir, Compilation &C, StringRef Target, const InputInfo &Output,
+ const InputInfo &Input, const llvm::opt::ArgList &Args) const;
+
public:
Clang(const ToolChain &TC);
~Clang() override;
@@ -148,6 +152,20 @@ public:
const llvm::opt::ArgList &TCArgs,
const char *LinkingOutput) const override;
};
+
+/// Offload wrapper tool.
+class LLVM_LIBRARY_VISIBILITY OffloadWrapper final : public Tool {
+public:
+ OffloadWrapper(const ToolChain &TC)
+ : Tool("offload wrapper", "clang-offload-wrapper", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+
} // end namespace tools
} // end namespace driver
diff --git a/lib/Driver/ToolChains/CloudABI.cpp b/lib/Driver/ToolChains/CloudABI.cpp
index cc1ac3ab7e79..cf1d0d551e57 100644
--- a/lib/Driver/ToolChains/CloudABI.cpp
+++ b/lib/Driver/ToolChains/CloudABI.cpp
@@ -92,7 +92,7 @@ void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
// CloudABI - CloudABI tool chain which can call ld(1) directly.
diff --git a/lib/Driver/ToolChains/CommonArgs.cpp b/lib/Driver/ToolChains/CommonArgs.cpp
index 99691cb43dc4..10743559e048 100644
--- a/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/lib/Driver/ToolChains/CommonArgs.cpp
@@ -11,8 +11,12 @@
#include "Arch/ARM.h"
#include "Arch/Mips.h"
#include "Arch/PPC.h"
+#include "Arch/RISCV.h"
+#include "Arch/Sparc.h"
#include "Arch/SystemZ.h"
#include "Arch/X86.h"
+#include "AMDGPU.h"
+#include "MSP430.h"
#include "HIP.h"
#include "Hexagon.h"
#include "InputInfo.h"
@@ -145,6 +149,11 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs,
// (constructed via -Xarch_).
Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input);
+ // LIBRARY_PATH are included before user inputs and only supported on native
+ // toolchains.
+ if (!TC.isCrossCompiling())
+ addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");
+
for (const auto &II : Inputs) {
// If the current tool chain refers to an OpenMP or HIP offloading host, we
// should ignore inputs that refer to OpenMP or HIP offloading devices -
@@ -182,12 +191,6 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs,
A.renderAsInput(Args, CmdArgs);
}
}
-
- // LIBRARY_PATH - included following the user specified library paths.
- // and only supported on native toolchains.
- if (!TC.isCrossCompiling()) {
- addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");
- }
}
void tools::AddTargetFeature(const ArgList &Args,
@@ -485,6 +488,14 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args,
if (!StatsFile.empty())
CmdArgs.push_back(
Args.MakeArgString(Twine("-plugin-opt=stats-file=") + StatsFile));
+
+ getTargetFeatures(ToolChain, ToolChain.getTriple(), Args, CmdArgs,
+ /* ForAS= */ false, /* ForLTOPlugin= */ true);
+
+ StringRef ABIName = tools::getTargetABI(Args, ToolChain.getTriple());
+ if (!ABIName.empty())
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-plugin-opt=-target-abi=") + ABIName));
}
void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args,
@@ -501,30 +512,41 @@ void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args,
}
bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
- const ArgList &Args, bool IsOffloadingHost,
- bool GompNeedsRT) {
+ const ArgList &Args, bool ForceStaticHostRuntime,
+ bool IsOffloadingHost, bool GompNeedsRT) {
if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
options::OPT_fno_openmp, false))
return false;
- switch (TC.getDriver().getOpenMPRuntime(Args)) {
+ Driver::OpenMPRuntimeKind RTKind = TC.getDriver().getOpenMPRuntime(Args);
+
+ if (RTKind == Driver::OMPRT_Unknown)
+ // Already diagnosed.
+ return false;
+
+ if (ForceStaticHostRuntime)
+ CmdArgs.push_back("-Bstatic");
+
+ switch (RTKind) {
case Driver::OMPRT_OMP:
CmdArgs.push_back("-lomp");
break;
case Driver::OMPRT_GOMP:
CmdArgs.push_back("-lgomp");
-
- if (GompNeedsRT)
- CmdArgs.push_back("-lrt");
break;
case Driver::OMPRT_IOMP5:
CmdArgs.push_back("-liomp5");
break;
case Driver::OMPRT_Unknown:
- // Already diagnosed.
- return false;
+ break;
}
+ if (ForceStaticHostRuntime)
+ CmdArgs.push_back("-Bdynamic");
+
+ if (RTKind == Driver::OMPRT_GOMP && GompNeedsRT)
+ CmdArgs.push_back("-lrt");
+
if (IsOffloadingHost)
CmdArgs.push_back("-lomptarget");
@@ -605,29 +627,29 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
// Collect shared runtimes.
if (SanArgs.needsSharedRt()) {
- if (SanArgs.needsAsanRt()) {
+ if (SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) {
SharedRuntimes.push_back("asan");
if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid())
HelperStaticRuntimes.push_back("asan-preinit");
}
- if (SanArgs.needsUbsanRt()) {
+ if (SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) {
if (SanArgs.requiresMinimalRuntime())
SharedRuntimes.push_back("ubsan_minimal");
else
SharedRuntimes.push_back("ubsan_standalone");
}
- if (SanArgs.needsScudoRt()) {
+ if (SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) {
if (SanArgs.requiresMinimalRuntime())
SharedRuntimes.push_back("scudo_minimal");
else
SharedRuntimes.push_back("scudo");
}
- if (SanArgs.needsHwasanRt())
+ if (SanArgs.needsHwasanRt() && SanArgs.linkRuntimes())
SharedRuntimes.push_back("hwasan");
}
// The stats_client library is also statically linked into DSOs.
- if (SanArgs.needsStatsRt())
+ if (SanArgs.needsStatsRt() && SanArgs.linkRuntimes())
StaticRuntimes.push_back("stats_client");
// Collect static runtimes.
@@ -635,32 +657,32 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
// Don't link static runtimes into DSOs or if -shared-libasan.
return;
}
- if (SanArgs.needsAsanRt()) {
+ if (SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) {
StaticRuntimes.push_back("asan");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("asan_cxx");
}
- if (SanArgs.needsHwasanRt()) {
+ if (SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) {
StaticRuntimes.push_back("hwasan");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("hwasan_cxx");
}
- if (SanArgs.needsDfsanRt())
+ if (SanArgs.needsDfsanRt() && SanArgs.linkRuntimes())
StaticRuntimes.push_back("dfsan");
- if (SanArgs.needsLsanRt())
+ if (SanArgs.needsLsanRt() && SanArgs.linkRuntimes())
StaticRuntimes.push_back("lsan");
- if (SanArgs.needsMsanRt()) {
+ if (SanArgs.needsMsanRt() && SanArgs.linkRuntimes()) {
StaticRuntimes.push_back("msan");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("msan_cxx");
}
- if (SanArgs.needsTsanRt()) {
+ if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes()) {
StaticRuntimes.push_back("tsan");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("tsan_cxx");
}
- if (SanArgs.needsUbsanRt()) {
+ if (SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) {
if (SanArgs.requiresMinimalRuntime()) {
StaticRuntimes.push_back("ubsan_minimal");
} else {
@@ -669,22 +691,22 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
StaticRuntimes.push_back("ubsan_standalone_cxx");
}
}
- if (SanArgs.needsSafeStackRt()) {
+ if (SanArgs.needsSafeStackRt() && SanArgs.linkRuntimes()) {
NonWholeStaticRuntimes.push_back("safestack");
RequiredSymbols.push_back("__safestack_init");
}
- if (SanArgs.needsCfiRt())
+ if (SanArgs.needsCfiRt() && SanArgs.linkRuntimes())
StaticRuntimes.push_back("cfi");
- if (SanArgs.needsCfiDiagRt()) {
+ if (SanArgs.needsCfiDiagRt() && SanArgs.linkRuntimes()) {
StaticRuntimes.push_back("cfi_diag");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("ubsan_standalone_cxx");
}
- if (SanArgs.needsStatsRt()) {
+ if (SanArgs.needsStatsRt() && SanArgs.linkRuntimes()) {
NonWholeStaticRuntimes.push_back("stats");
RequiredSymbols.push_back("__sanitizer_stats_register");
}
- if (SanArgs.needsScudoRt()) {
+ if (SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) {
if (SanArgs.requiresMinimalRuntime()) {
StaticRuntimes.push_back("scudo_minimal");
if (SanArgs.linkCXXRuntimes())
@@ -707,9 +729,10 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
NonWholeStaticRuntimes, HelperStaticRuntimes,
RequiredSymbols);
+ const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
// Inject libfuzzer dependencies.
- if (TC.getSanitizerArgs().needsFuzzer()
- && !Args.hasArg(options::OPT_shared)) {
+ if (SanArgs.needsFuzzer() && SanArgs.linkRuntimes() &&
+ !Args.hasArg(options::OPT_shared)) {
addSanitizerRuntime(TC, Args, CmdArgs, "fuzzer", false, true);
if (!Args.hasArg(clang::driver::options::OPT_nostdlibxx))
@@ -738,7 +761,6 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
if (AddExportDynamic)
CmdArgs.push_back("--export-dynamic");
- const SanitizerArgs &SanArgs = TC.getSanitizerArgs();
if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic)
CmdArgs.push_back("-export-dynamic-symbol=__cfi_check");
@@ -823,10 +845,10 @@ void tools::SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T,
InputInfo II(types::TY_Object, Output.getFilename(), Output.getFilename());
// First extract the dwo sections.
- C.addCommand(llvm::make_unique<Command>(JA, T, Exec, ExtractArgs, II));
+ C.addCommand(std::make_unique<Command>(JA, T, Exec, ExtractArgs, II));
// Then remove them from the original .o file.
- C.addCommand(llvm::make_unique<Command>(JA, T, Exec, StripArgs, II));
+ C.addCommand(std::make_unique<Command>(JA, T, Exec, StripArgs, II));
}
// Claim options we don't want to warn if they are unused. We do this for
@@ -1176,7 +1198,6 @@ static void AddUnwindLibrary(const ToolChain &TC, const Driver &D,
case ToolChain::UNW_None:
return;
case ToolChain::UNW_Libgcc: {
- LibGccType LGT = getLibGccType(D, Args);
if (LGT == LibGccType::StaticLibGcc)
CmdArgs.push_back("-lgcc_eh");
else
@@ -1235,131 +1256,6 @@ void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D,
}
}
-/// Add OpenMP linker script arguments at the end of the argument list so that
-/// the fat binary is built by embedding each of the device images into the
-/// host. The linker script also defines a few symbols required by the code
-/// generation so that the images can be easily retrieved at runtime by the
-/// offloading library. This should be used only in tool chains that support
-/// linker scripts.
-void tools::AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args, ArgStringList &CmdArgs,
- const JobAction &JA) {
-
- // If this is not an OpenMP host toolchain, we don't need to do anything.
- if (!JA.isHostOffloading(Action::OFK_OpenMP))
- return;
-
- // Create temporary linker script. Keep it if save-temps is enabled.
- const char *LKS;
- SmallString<256> Name = llvm::sys::path::filename(Output.getFilename());
- if (C.getDriver().isSaveTempsEnabled()) {
- llvm::sys::path::replace_extension(Name, "lk");
- LKS = C.getArgs().MakeArgString(Name.c_str());
- } else {
- llvm::sys::path::replace_extension(Name, "");
- Name = C.getDriver().GetTemporaryPath(Name, "lk");
- LKS = C.addTempFile(C.getArgs().MakeArgString(Name.c_str()));
- }
-
- // Add linker script option to the command.
- CmdArgs.push_back("-T");
- CmdArgs.push_back(LKS);
-
- // Create a buffer to write the contents of the linker script.
- std::string LksBuffer;
- llvm::raw_string_ostream LksStream(LksBuffer);
-
- // Get the OpenMP offload tool chains so that we can extract the triple
- // associated with each device input.
- auto OpenMPToolChains = C.getOffloadToolChains<Action::OFK_OpenMP>();
- assert(OpenMPToolChains.first != OpenMPToolChains.second &&
- "No OpenMP toolchains??");
-
- // Track the input file name and device triple in order to build the script,
- // inserting binaries in the designated sections.
- SmallVector<std::pair<std::string, const char *>, 8> InputBinaryInfo;
-
- // Add commands to embed target binaries. We ensure that each section and
- // image is 16-byte aligned. This is not mandatory, but increases the
- // likelihood of data to be aligned with a cache block in several main host
- // machines.
- LksStream << "/*\n";
- LksStream << " OpenMP Offload Linker Script\n";
- LksStream << " *** Automatically generated by Clang ***\n";
- LksStream << "*/\n";
- LksStream << "TARGET(binary)\n";
- auto DTC = OpenMPToolChains.first;
- for (auto &II : Inputs) {
- const Action *A = II.getAction();
- // Is this a device linking action?
- if (A && isa<LinkJobAction>(A) &&
- A->isDeviceOffloading(Action::OFK_OpenMP)) {
- assert(DTC != OpenMPToolChains.second &&
- "More device inputs than device toolchains??");
- InputBinaryInfo.push_back(std::make_pair(
- DTC->second->getTriple().normalize(), II.getFilename()));
- ++DTC;
- LksStream << "INPUT(" << II.getFilename() << ")\n";
- }
- }
-
- assert(DTC == OpenMPToolChains.second &&
- "Less device inputs than device toolchains??");
-
- LksStream << "SECTIONS\n";
- LksStream << "{\n";
-
- // Put each target binary into a separate section.
- for (const auto &BI : InputBinaryInfo) {
- LksStream << " .omp_offloading." << BI.first << " :\n";
- LksStream << " ALIGN(0x10)\n";
- LksStream << " {\n";
- LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_start." << BI.first
- << " = .);\n";
- LksStream << " " << BI.second << "\n";
- LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_end." << BI.first
- << " = .);\n";
- LksStream << " }\n";
- }
-
- // Add commands to define host entries begin and end. We use 1-byte subalign
- // so that the linker does not add any padding and the elements in this
- // section form an array.
- LksStream << " .omp_offloading.entries :\n";
- LksStream << " ALIGN(0x10)\n";
- LksStream << " SUBALIGN(0x01)\n";
- LksStream << " {\n";
- LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_begin = .);\n";
- LksStream << " *(.omp_offloading.entries)\n";
- LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_end = .);\n";
- LksStream << " }\n";
- LksStream << "}\n";
- LksStream << "INSERT BEFORE .data\n";
- LksStream.flush();
-
- // Dump the contents of the linker script if the user requested that. We
- // support this option to enable testing of behavior with -###.
- if (C.getArgs().hasArg(options::OPT_fopenmp_dump_offload_linker_script))
- llvm::errs() << LksBuffer;
-
- // If this is a dry run, do not create the linker script file.
- if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH))
- return;
-
- // Open script file and write the contents.
- std::error_code EC;
- llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::F_None);
-
- if (EC) {
- C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message();
- return;
- }
-
- Lksf << LksBuffer;
-}
-
/// Add HIP linker script arguments at the end of the argument list so that
/// the fat binary is built by embedding the device images into the host. The
/// linker script also defines a symbol required by the code generation so that
@@ -1389,14 +1285,12 @@ void tools::AddHIPLinkerScript(const ToolChain &TC, Compilation &C,
// Create temporary linker script. Keep it if save-temps is enabled.
const char *LKS;
- SmallString<256> Name = llvm::sys::path::filename(Output.getFilename());
+ std::string Name = llvm::sys::path::filename(Output.getFilename());
if (C.getDriver().isSaveTempsEnabled()) {
- llvm::sys::path::replace_extension(Name, "lk");
- LKS = C.getArgs().MakeArgString(Name.c_str());
+ LKS = C.getArgs().MakeArgString(Name + ".lk");
} else {
- llvm::sys::path::replace_extension(Name, "");
- Name = C.getDriver().GetTemporaryPath(Name, "lk");
- LKS = C.addTempFile(C.getArgs().MakeArgString(Name.c_str()));
+ auto TmpName = C.getDriver().GetTemporaryPath(Name, "lk");
+ LKS = C.addTempFile(C.getArgs().MakeArgString(TmpName));
}
// Add linker script option to the command.
@@ -1414,11 +1308,13 @@ void tools::AddHIPLinkerScript(const ToolChain &TC, Compilation &C,
"Wrong platform");
(void)HIPTC;
- // The output file name needs to persist through the compilation, therefore
- // it needs to be created through MakeArgString.
- std::string BundleFileName = C.getDriver().GetTemporaryPath("BUNDLE", "hipfb");
- const char *BundleFile =
- C.addTempFile(C.getArgs().MakeArgString(BundleFileName.c_str()));
+ const char *BundleFile;
+ if (C.getDriver().isSaveTempsEnabled()) {
+ BundleFile = C.getArgs().MakeArgString(Name + ".hipfb");
+ } else {
+ auto TmpName = C.getDriver().GetTemporaryPath(Name, "hipfb");
+ BundleFile = C.addTempFile(C.getArgs().MakeArgString(TmpName));
+ }
AMDGCN::constructHIPFatbinCommand(C, JA, BundleFile, DeviceInputs, Args, T);
// Add commands to embed target binaries. We ensure that each section and
@@ -1430,14 +1326,14 @@ void tools::AddHIPLinkerScript(const ToolChain &TC, Compilation &C,
LksStream << " *** Automatically generated by Clang ***\n";
LksStream << "*/\n";
LksStream << "TARGET(binary)\n";
- LksStream << "INPUT(" << BundleFileName << ")\n";
+ LksStream << "INPUT(" << BundleFile << ")\n";
LksStream << "SECTIONS\n";
LksStream << "{\n";
LksStream << " .hip_fatbin :\n";
LksStream << " ALIGN(0x10)\n";
LksStream << " {\n";
LksStream << " PROVIDE_HIDDEN(__hip_fatbin = .);\n";
- LksStream << " " << BundleFileName << "\n";
+ LksStream << " " << BundleFile << "\n";
LksStream << " }\n";
LksStream << " /DISCARD/ :\n";
LksStream << " {\n";
@@ -1458,7 +1354,7 @@ void tools::AddHIPLinkerScript(const ToolChain &TC, Compilation &C,
// Open script file and write the contents.
std::error_code EC;
- llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::F_None);
+ llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::OF_None);
if (EC) {
C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message();
@@ -1496,3 +1392,111 @@ void tools::addMultilibFlag(bool Enabled, const char *const Flag,
Multilib::flags_list &Flags) {
Flags.push_back(std::string(Enabled ? "+" : "-") + Flag);
}
+
+static void getWebAssemblyTargetFeatures(const ArgList &Args,
+ std::vector<StringRef> &Features) {
+ handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group);
+}
+
+void tools::getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple,
+ const ArgList &Args, ArgStringList &CmdArgs, bool ForAS,
+ bool ForLTOPlugin) {
+
+ const Driver &D = TC.getDriver();
+ std::vector<StringRef> Features;
+ switch (Triple.getArch()) {
+ default:
+ break;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ mips::getMIPSTargetFeatures(D, Triple, Args, Features);
+ break;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ arm::getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS);
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::ppc64le:
+ ppc::getPPCTargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::riscv32:
+ case llvm::Triple::riscv64:
+ riscv::getRISCVTargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::systemz:
+ systemz::getSystemZTargetFeatures(Args, Features);
+ break;
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ aarch64::getAArch64TargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ x86::getX86TargetFeatures(D, Triple, Args, Features);
+ break;
+ case llvm::Triple::hexagon:
+ hexagon::getHexagonTargetFeatures(D, Args, Features);
+ break;
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ getWebAssemblyTargetFeatures(Args, Features);
+ break;
+ case llvm::Triple::sparc:
+ case llvm::Triple::sparcel:
+ case llvm::Triple::sparcv9:
+ sparc::getSparcTargetFeatures(D, Args, Features);
+ break;
+ case llvm::Triple::r600:
+ case llvm::Triple::amdgcn:
+ amdgpu::getAMDGPUTargetFeatures(D, Args, Features);
+ break;
+ case llvm::Triple::msp430:
+ msp430::getMSP430TargetFeatures(D, Args, Features);
+ }
+
+ // Find the last of each feature.
+ llvm::StringMap<unsigned> LastOpt;
+ for (unsigned I = 0, N = Features.size(); I < N; ++I) {
+ StringRef Name = Features[I];
+ assert(Name[0] == '-' || Name[0] == '+');
+ LastOpt[Name.drop_front(1)] = I;
+ }
+
+ for (unsigned I = 0, N = Features.size(); I < N; ++I) {
+ // If this feature was overridden, ignore it.
+ StringRef Name = Features[I];
+ llvm::StringMap<unsigned>::iterator LastI =
+ LastOpt.find(Name.drop_front(1));
+ assert(LastI != LastOpt.end());
+ unsigned Last = LastI->second;
+ if (Last != I)
+ continue;
+ if (!ForLTOPlugin) {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back(Name.data());
+ } else {
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-plugin-opt=-mattr=") + Name));
+ }
+ }
+}
+
+StringRef tools::getTargetABI(const ArgList &Args, const llvm::Triple &Triple) {
+ // TODO: Support the other target ABI
+ switch (Triple.getArch()) {
+ default:
+ break;
+ case llvm::Triple::riscv32:
+ case llvm::Triple::riscv64:
+ return tools::riscv::getRISCVABI(Args, Triple);
+ break;
+ }
+ return StringRef();
+}
diff --git a/lib/Driver/ToolChains/CommonArgs.h b/lib/Driver/ToolChains/CommonArgs.h
index 9a311708f3ae..79468e6b8926 100644
--- a/lib/Driver/ToolChains/CommonArgs.h
+++ b/lib/Driver/ToolChains/CommonArgs.h
@@ -45,13 +45,6 @@ void AddRunTimeLibs(const ToolChain &TC, const Driver &D,
llvm::opt::ArgStringList &CmdArgs,
const llvm::opt::ArgList &Args);
-void AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs,
- const JobAction &JA);
-
void AddHIPLinkerScript(const ToolChain &TC, Compilation &C,
const InputInfo &Output, const InputInfoList &Inputs,
const llvm::opt::ArgList &Args,
@@ -84,6 +77,7 @@ void addArchSpecificRPath(const ToolChain &TC, const llvm::opt::ArgList &Args,
/// Returns true, if an OpenMP runtime has been added.
bool addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC,
const llvm::opt::ArgList &Args,
+ bool ForceStaticHostRuntime = false,
bool IsOffloadingHost = false, bool GompNeedsRT = false);
llvm::opt::Arg *getLastProfileUseArg(const llvm::opt::ArgList &Args);
@@ -124,6 +118,14 @@ SmallString<128> getStatsFileName(const llvm::opt::ArgList &Args,
void addMultilibFlag(bool Enabled, const char *const Flag,
Multilib::flags_list &Flags);
+StringRef getTargetABI(const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple);
+
+void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple,
+ const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs, bool ForAS,
+ bool ForLTOPlugin = false);
+
} // end namespace tools
} // end namespace driver
} // end namespace clang
diff --git a/lib/Driver/ToolChains/CrossWindows.cpp b/lib/Driver/ToolChains/CrossWindows.cpp
index bd3a6e11c928..dbf6114eb2ec 100644
--- a/lib/Driver/ToolChains/CrossWindows.cpp
+++ b/lib/Driver/ToolChains/CrossWindows.cpp
@@ -57,7 +57,7 @@ void tools::CrossWindows::Assembler::ConstructJob(
const std::string Assembler = TC.GetProgramPath("as");
Exec = Args.MakeArgString(Assembler);
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void tools::CrossWindows::Linker::ConstructJob(
@@ -202,7 +202,7 @@ void tools::CrossWindows::Linker::ConstructJob(
Exec = Args.MakeArgString(TC.GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D,
diff --git a/lib/Driver/ToolChains/Cuda.cpp b/lib/Driver/ToolChains/Cuda.cpp
index 96f8c513bb56..8c704a3078ad 100644
--- a/lib/Driver/ToolChains/Cuda.cpp
+++ b/lib/Driver/ToolChains/Cuda.cpp
@@ -121,7 +121,7 @@ CudaInstallationDetector::CudaInstallationDetector(
Candidates.emplace_back(D.SysRoot + "/usr/lib/cuda");
}
- bool NoCudaLib = Args.hasArg(options::OPT_nocudalib);
+ bool NoCudaLib = Args.hasArg(options::OPT_nogpulib);
for (const auto &Candidate : Candidates) {
InstallPath = Candidate.Path;
@@ -422,7 +422,7 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
Exec = A->getValue();
else
Exec = Args.MakeArgString(TC.GetProgramPath("ptxas"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
static bool shouldIncludePTX(const ArgList &Args, const char *gpu_arch) {
@@ -488,7 +488,7 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(A));
const char *Exec = Args.MakeArgString(TC.GetProgramPath("fatbinary"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -563,11 +563,9 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(CubinF);
}
- AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA);
-
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("nvlink"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
/// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary,
@@ -628,7 +626,7 @@ void CudaToolChain::addClangTargetOptions(
CC1Args.push_back("-fgpu-rdc");
}
- if (DriverArgs.hasArg(options::OPT_nocudalib))
+ if (DriverArgs.hasArg(options::OPT_nogpulib))
return;
std::string LibDeviceFile = CudaInstallation.getLibDeviceFile(GpuArch);
diff --git a/lib/Driver/ToolChains/Darwin.cpp b/lib/Driver/ToolChains/Darwin.cpp
index 5de7d7132df8..ee08b8208d93 100644
--- a/lib/Driver/ToolChains/Darwin.cpp
+++ b/lib/Driver/ToolChains/Darwin.cpp
@@ -146,7 +146,7 @@ void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
// asm_final spec is empty.
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void darwin::MachOTool::anchor() {}
@@ -451,7 +451,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("touch"));
CmdArgs.push_back(Output.getFilename());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, None));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, None));
return;
}
@@ -653,7 +653,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
std::unique_ptr<Command> Cmd =
- llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs);
+ std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs);
Cmd->setInputFileList(std::move(InputFileList));
C.addCommand(std::move(Cmd));
}
@@ -677,7 +677,7 @@ void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("lipo"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA,
@@ -697,7 +697,7 @@ void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("dsymutil"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA,
@@ -720,7 +720,7 @@ void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("dwarfdump"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
MachO::MachO(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
@@ -1128,7 +1128,6 @@ void Darwin::addProfileRTLibs(const ArgList &Args,
} else {
addExportedSymbol(CmdArgs, "___llvm_profile_filename");
addExportedSymbol(CmdArgs, "___llvm_profile_raw_version");
- addExportedSymbol(CmdArgs, "_lprofCurFilename");
}
addExportedSymbol(CmdArgs, "_lprofDirMode");
}
@@ -1480,22 +1479,6 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver,
Targets[I.index()] = Env;
}
- // Do not allow conflicts with the watchOS target.
- if (!Targets[Darwin::WatchOS].empty() &&
- (!Targets[Darwin::IPhoneOS].empty() || !Targets[Darwin::TvOS].empty())) {
- TheDriver.Diag(diag::err_drv_conflicting_deployment_targets)
- << "WATCHOS_DEPLOYMENT_TARGET"
- << (!Targets[Darwin::IPhoneOS].empty() ? "IPHONEOS_DEPLOYMENT_TARGET"
- : "TVOS_DEPLOYMENT_TARGET");
- }
-
- // Do not allow conflicts with the tvOS target.
- if (!Targets[Darwin::TvOS].empty() && !Targets[Darwin::IPhoneOS].empty()) {
- TheDriver.Diag(diag::err_drv_conflicting_deployment_targets)
- << "TVOS_DEPLOYMENT_TARGET"
- << "IPHONEOS_DEPLOYMENT_TARGET";
- }
-
// Allow conflicts among OSX and iOS for historical reasons, but choose the
// default platform.
if (!Targets[Darwin::MacOS].empty() &&
@@ -1508,6 +1491,18 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver,
else
Targets[Darwin::IPhoneOS] = Targets[Darwin::WatchOS] =
Targets[Darwin::TvOS] = "";
+ } else {
+ // Don't allow conflicts in any other platform.
+ int FirstTarget = llvm::array_lengthof(Targets);
+ for (int I = 0; I != llvm::array_lengthof(Targets); ++I) {
+ if (Targets[I].empty())
+ continue;
+ if (FirstTarget == llvm::array_lengthof(Targets))
+ FirstTarget = I;
+ else
+ TheDriver.Diag(diag::err_drv_conflicting_deployment_targets)
+ << Targets[FirstTarget] << Targets[I];
+ }
}
for (const auto &Target : llvm::enumerate(llvm::makeArrayRef(Targets))) {
diff --git a/lib/Driver/ToolChains/DragonFly.cpp b/lib/Driver/ToolChains/DragonFly.cpp
index 0a7c8b1615e7..424331fbc6fe 100644
--- a/lib/Driver/ToolChains/DragonFly.cpp
+++ b/lib/Driver/ToolChains/DragonFly.cpp
@@ -45,7 +45,7 @@ void dragonfly::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -169,7 +169,7 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().addProfileRTLibs(Args, CmdArgs);
const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
/// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly.
diff --git a/lib/Driver/ToolChains/FreeBSD.cpp b/lib/Driver/ToolChains/FreeBSD.cpp
index 3a0bab8d07f5..7c891a24ba30 100644
--- a/lib/Driver/ToolChains/FreeBSD.cpp
+++ b/lib/Driver/ToolChains/FreeBSD.cpp
@@ -112,7 +112,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -197,6 +197,14 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back("elf64ltsmip_fbsd");
break;
+ case llvm::Triple::riscv32:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf32lriscv");
+ break;
+ case llvm::Triple::riscv64:
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("elf64lriscv");
+ break;
default:
break;
}
@@ -262,7 +270,11 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- addOpenMPRuntime(CmdArgs, ToolChain, Args);
+ // Use the static OpenMP runtime with -static-openmp
+ bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
+ !Args.hasArg(options::OPT_static);
+ addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP);
+
if (D.CCCIsCXX()) {
if (ToolChain.ShouldLinkCXXStdlib(Args))
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
@@ -331,7 +343,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
ToolChain.addProfileRTLibs(Args, CmdArgs);
const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
/// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly.
@@ -356,6 +368,12 @@ ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const {
return ToolChain::CST_Libstdcxx;
}
+unsigned FreeBSD::GetDefaultDwarfVersion() const {
+ if (getTriple().getOSMajorVersion() < 12)
+ return 2;
+ return 4;
+}
+
void FreeBSD::addLibStdCxxIncludePaths(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
diff --git a/lib/Driver/ToolChains/FreeBSD.h b/lib/Driver/ToolChains/FreeBSD.h
index adfe21da372f..d17b3808ffac 100644
--- a/lib/Driver/ToolChains/FreeBSD.h
+++ b/lib/Driver/ToolChains/FreeBSD.h
@@ -69,7 +69,7 @@ public:
const llvm::opt::ArgList &Args) const override;
bool isPIEDefault() const override;
SanitizerMask getSupportedSanitizers() const override;
- unsigned GetDefaultDwarfVersion() const override { return 2; }
+ unsigned GetDefaultDwarfVersion() const override;
// Until dtrace (via CTF) and LLDB can deal with distributed debug info,
// FreeBSD defaults to standalone/full debug info.
bool GetDefaultStandaloneDebug() const override { return true; }
diff --git a/lib/Driver/ToolChains/Fuchsia.cpp b/lib/Driver/ToolChains/Fuchsia.cpp
index 1f5ec9ebb16d..e7d38ff9f227 100644
--- a/lib/Driver/ToolChains/Fuchsia.cpp
+++ b/lib/Driver/ToolChains/Fuchsia.cpp
@@ -51,6 +51,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
llvm::sys::path::stem(Exec).equals_lower("ld.lld")) {
CmdArgs.push_back("-z");
CmdArgs.push_back("rodynamic");
+ CmdArgs.push_back("-z");
+ CmdArgs.push_back("separate-loadable-segments");
}
if (!D.SysRoot.empty())
@@ -154,7 +156,7 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lc");
}
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
/// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly.
diff --git a/lib/Driver/ToolChains/Fuchsia.h b/lib/Driver/ToolChains/Fuchsia.h
index dd7c5c650352..fee0e018f3ce 100644
--- a/lib/Driver/ToolChains/Fuchsia.h
+++ b/lib/Driver/ToolChains/Fuchsia.h
@@ -17,9 +17,9 @@ namespace clang {
namespace driver {
namespace tools {
namespace fuchsia {
-class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
public:
- Linker(const ToolChain &TC) : GnuTool("fuchsia::Linker", "ld.lld", TC) {}
+ Linker(const ToolChain &TC) : Tool("fuchsia::Linker", "ld.lld", TC) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp
index 33cdd3585c29..c302a31cd2e1 100644
--- a/lib/Driver/ToolChains/Gnu.cpp
+++ b/lib/Driver/ToolChains/Gnu.cpp
@@ -189,7 +189,7 @@ void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
GCCName = "gcc";
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void tools::gcc::Preprocessor::RenderExtraToolArgs(
@@ -499,7 +499,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
P = ToolChain.GetFilePath(crtbegin);
}
CmdArgs.push_back(Args.MakeArgString(P));
- }
+ }
// Add crtfastmath.o if available and fast math is enabled.
ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs);
@@ -555,9 +555,13 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
bool WantPthread = Args.hasArg(options::OPT_pthread) ||
Args.hasArg(options::OPT_pthreads);
+ // Use the static OpenMP runtime with -static-openmp
+ bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
+ !Args.hasArg(options::OPT_static);
+
// FIXME: Only pass GompNeedsRT = true for platforms with libgomp that
// require librt. Most modern Linux platforms do, but some may not.
- if (addOpenMPRuntime(CmdArgs, ToolChain, Args,
+ if (addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP,
JA.isHostOffloading(Action::OFK_OpenMP),
/* GompNeedsRT= */ true))
// OpenMP runtimes implies pthreads when using the GNU toolchain.
@@ -619,15 +623,12 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- // Add OpenMP offloading linker script args if required.
- AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA);
-
// Add HIP offloading linker script args if required.
AddHIPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA,
*this);
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void tools::gnutools::Assembler::ConstructJob(Compilation &C,
@@ -819,7 +820,8 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
A->render(Args, CmdArgs);
} else if (mips::shouldUseFPXX(
Args, getToolChain().getTriple(), CPUName, ABIName,
- mips::getMipsFloatABI(getToolChain().getDriver(), Args)))
+ mips::getMipsFloatABI(getToolChain().getDriver(), Args,
+ getToolChain().getTriple())))
CmdArgs.push_back("-mfpxx");
// Pass on -mmips16 or -mno-mips16. However, the assembler equivalent of
@@ -878,7 +880,7 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
// Handle the debug info splitting at object creation time if we're
// creating an object.
@@ -2017,7 +2019,8 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
static const char *const RISCV64LibDirs[] = {"/lib64", "/lib"};
static const char *const RISCV64Triples[] = {"riscv64-unknown-linux-gnu",
"riscv64-linux-gnu",
- "riscv64-unknown-elf"};
+ "riscv64-unknown-elf",
+ "riscv64-suse-linux"};
static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"};
static const char *const SPARCv8Triples[] = {"sparc-linux-gnu",
diff --git a/lib/Driver/ToolChains/HIP.cpp b/lib/Driver/ToolChains/HIP.cpp
index 2ec97e798fd0..ad9384df6a24 100644
--- a/lib/Driver/ToolChains/HIP.cpp
+++ b/lib/Driver/ToolChains/HIP.cpp
@@ -23,7 +23,7 @@ using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
-#if _WIN32 || _WIN64
+#if defined(_WIN32) || defined(_WIN64)
#define NULL_FILE "nul"
#else
#define NULL_FILE "/dev/null"
@@ -48,6 +48,20 @@ static void addBCLib(const Driver &D, const ArgList &Args,
D.Diag(diag::err_drv_no_such_file) << BCName;
}
+static const char *getOutputFileName(Compilation &C, StringRef Base,
+ const char *Postfix,
+ const char *Extension) {
+ const char *OutputFileName;
+ if (C.getDriver().isSaveTempsEnabled()) {
+ OutputFileName =
+ C.getArgs().MakeArgString(Base.str() + Postfix + "." + Extension);
+ } else {
+ std::string TmpName =
+ C.getDriver().GetTemporaryPath(Base.str() + Postfix, Extension);
+ OutputFileName = C.addTempFile(C.getArgs().MakeArgString(TmpName));
+ }
+ return OutputFileName;
+}
} // namespace
const char *AMDGCN::Linker::constructLLVMLinkCommand(
@@ -61,15 +75,12 @@ const char *AMDGCN::Linker::constructLLVMLinkCommand(
// Add an intermediate output file.
CmdArgs.push_back("-o");
- std::string TmpName =
- C.getDriver().GetTemporaryPath(OutputFilePrefix.str() + "-linked", "bc");
- const char *OutputFileName =
- C.addTempFile(C.getArgs().MakeArgString(TmpName));
+ auto OutputFileName = getOutputFileName(C, OutputFilePrefix, "-linked", "bc");
CmdArgs.push_back(OutputFileName);
SmallString<128> ExecPath(C.getDriver().Dir);
llvm::sys::path::append(ExecPath, "llvm-link");
const char *Exec = Args.MakeArgString(ExecPath);
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
return OutputFileName;
}
@@ -109,26 +120,26 @@ const char *AMDGCN::Linker::constructOptCommand(
}
OptArgs.push_back("-o");
- std::string TmpFileName = C.getDriver().GetTemporaryPath(
- OutputFilePrefix.str() + "-optimized", "bc");
- const char *OutputFileName =
- C.addTempFile(C.getArgs().MakeArgString(TmpFileName));
+ auto OutputFileName =
+ getOutputFileName(C, OutputFilePrefix, "-optimized", "bc");
OptArgs.push_back(OutputFileName);
SmallString<128> OptPath(C.getDriver().Dir);
llvm::sys::path::append(OptPath, "opt");
const char *OptExec = Args.MakeArgString(OptPath);
- C.addCommand(llvm::make_unique<Command>(JA, *this, OptExec, OptArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, OptExec, OptArgs, Inputs));
return OutputFileName;
}
const char *AMDGCN::Linker::constructLlcCommand(
Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
const llvm::opt::ArgList &Args, llvm::StringRef SubArchName,
- llvm::StringRef OutputFilePrefix, const char *InputFileName) const {
+ llvm::StringRef OutputFilePrefix, const char *InputFileName,
+ bool OutputIsAsm) const {
// Construct llc command.
- ArgStringList LlcArgs{InputFileName, "-mtriple=amdgcn-amd-amdhsa",
- "-filetype=obj",
- Args.MakeArgString("-mcpu=" + SubArchName)};
+ ArgStringList LlcArgs{
+ InputFileName, "-mtriple=amdgcn-amd-amdhsa",
+ Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj")),
+ Args.MakeArgString("-mcpu=" + SubArchName)};
// Extract all the -m options
std::vector<llvm::StringRef> Features;
@@ -151,15 +162,13 @@ const char *AMDGCN::Linker::constructLlcCommand(
// Add output filename
LlcArgs.push_back("-o");
- std::string LlcOutputFileName =
- C.getDriver().GetTemporaryPath(OutputFilePrefix, "o");
- const char *LlcOutputFile =
- C.addTempFile(C.getArgs().MakeArgString(LlcOutputFileName));
+ auto LlcOutputFile =
+ getOutputFileName(C, OutputFilePrefix, "", OutputIsAsm ? "s" : "o");
LlcArgs.push_back(LlcOutputFile);
SmallString<128> LlcPath(C.getDriver().Dir);
llvm::sys::path::append(LlcPath, "llc");
const char *Llc = Args.MakeArgString(LlcPath);
- C.addCommand(llvm::make_unique<Command>(JA, *this, Llc, LlcArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Llc, LlcArgs, Inputs));
return LlcOutputFile;
}
@@ -175,7 +184,7 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA,
SmallString<128> LldPath(C.getDriver().Dir);
llvm::sys::path::append(LldPath, "lld");
const char *Lld = Args.MakeArgString(LldPath);
- C.addCommand(llvm::make_unique<Command>(JA, *this, Lld, LldArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Lld, LldArgs, Inputs));
}
// Construct a clang-offload-bundler command to bundle code objects for
@@ -209,7 +218,7 @@ void AMDGCN::constructHIPFatbinCommand(Compilation &C, const JobAction &JA,
SmallString<128> BundlerPath(C.getDriver().Dir);
llvm::sys::path::append(BundlerPath, "clang-offload-bundler");
const char *Bundler = Args.MakeArgString(BundlerPath);
- C.addCommand(llvm::make_unique<Command>(JA, T, Bundler, BundlerArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, T, Bundler, BundlerArgs, Inputs));
}
// For amdgcn the inputs of the linker job are device bitcode and output is
@@ -230,14 +239,18 @@ void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA,
assert(StringRef(SubArchName).startswith("gfx") && "Unsupported sub arch");
// Prefix for temporary file name.
- std::string Prefix =
- llvm::sys::path::stem(Inputs[0].getFilename()).str() + "-" + SubArchName;
+ std::string Prefix = llvm::sys::path::stem(Inputs[0].getFilename()).str();
+ if (!C.getDriver().isSaveTempsEnabled())
+ Prefix += "-" + SubArchName;
// Each command outputs different files.
const char *LLVMLinkCommand =
constructLLVMLinkCommand(C, JA, Inputs, Args, SubArchName, Prefix);
const char *OptCommand = constructOptCommand(C, JA, Inputs, Args, SubArchName,
Prefix, LLVMLinkCommand);
+ if (C.getDriver().isSaveTempsEnabled())
+ constructLlcCommand(C, JA, Inputs, Args, SubArchName, Prefix, OptCommand,
+ /*OutputIsAsm=*/true);
const char *LlcCommand =
constructLlcCommand(C, JA, Inputs, Args, SubArchName, Prefix, OptCommand);
constructLldCommand(C, JA, Inputs, Output, Args, LlcCommand);
@@ -286,6 +299,9 @@ void HIPToolChain::addClangTargetOptions(
CC1Args.append({"-fvisibility", "hidden"});
CC1Args.push_back("-fapply-global-visibility-to-externs");
}
+
+ if (DriverArgs.hasArg(options::OPT_nogpulib))
+ return;
ArgStringList LibraryPaths;
// Find in --hip-device-lib-path and HIP_LIBRARY_PATH.
diff --git a/lib/Driver/ToolChains/HIP.h b/lib/Driver/ToolChains/HIP.h
index a650095d054d..2d146ce5cc6f 100644
--- a/lib/Driver/ToolChains/HIP.h
+++ b/lib/Driver/ToolChains/HIP.h
@@ -58,7 +58,8 @@ private:
const llvm::opt::ArgList &Args,
llvm::StringRef SubArchName,
llvm::StringRef OutputFilePrefix,
- const char *InputFileName) const;
+ const char *InputFileName,
+ bool OutputIsAsm = false) const;
void constructLldCommand(Compilation &C, const JobAction &JA,
const InputInfoList &Inputs, const InputInfo &Output,
diff --git a/lib/Driver/ToolChains/Hexagon.cpp b/lib/Driver/ToolChains/Hexagon.cpp
index f2c3ea11a9f3..96cc084e2821 100644
--- a/lib/Driver/ToolChains/Hexagon.cpp
+++ b/lib/Driver/ToolChains/Hexagon.cpp
@@ -183,7 +183,7 @@ void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
}
auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
@@ -370,7 +370,7 @@ void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA,
LinkingOutput);
const char *Exec = Args.MakeArgString(HTC.GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
// Hexagon tools end.
diff --git a/lib/Driver/ToolChains/InterfaceStubs.cpp b/lib/Driver/ToolChains/InterfaceStubs.cpp
new file mode 100644
index 000000000000..6677843b2c53
--- /dev/null
+++ b/lib/Driver/ToolChains/InterfaceStubs.cpp
@@ -0,0 +1,37 @@
+//===--- InterfaceStubs.cpp - Base InterfaceStubs Implementations C++ ---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "InterfaceStubs.h"
+#include "CommonArgs.h"
+#include "clang/Driver/Compilation.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace ifstool {
+void Merger::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &Args,
+ const char *LinkingOutput) const {
+ std::string Merger = getToolChain().GetProgramPath(getShortName());
+ llvm::opt::ArgStringList CmdArgs;
+ CmdArgs.push_back("-action");
+ CmdArgs.push_back(Args.getLastArg(options::OPT_emit_merged_ifs)
+ ? "write-ifs"
+ : "write-bin");
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+ for (const auto &Input : Inputs)
+ CmdArgs.push_back(Input.getFilename());
+ C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Merger),
+ CmdArgs, Inputs));
+}
+} // namespace ifstool
+} // namespace tools
+} // namespace driver
+} // namespace clang
diff --git a/lib/Driver/ToolChains/InterfaceStubs.h b/lib/Driver/ToolChains/InterfaceStubs.h
new file mode 100644
index 000000000000..4afa73701a4c
--- /dev/null
+++ b/lib/Driver/ToolChains/InterfaceStubs.h
@@ -0,0 +1,36 @@
+//===--- InterfaceStubs.cpp - Base InterfaceStubs Implementations C++ ---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_IFS_H
+#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_IFS_H
+
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
+
+namespace clang {
+namespace driver {
+namespace tools {
+namespace ifstool {
+class LLVM_LIBRARY_VISIBILITY Merger : public Tool {
+public:
+ Merger(const ToolChain &TC) : Tool("IFS::Merger", "llvm-ifs", TC) {}
+
+ bool hasIntegratedCPP() const override { return false; }
+ bool isLinkJob() const override { return false; }
+
+ void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output, const InputInfoList &Inputs,
+ const llvm::opt::ArgList &TCArgs,
+ const char *LinkingOutput) const override;
+};
+} // end namespace ifstool
+} // end namespace tools
+} // end namespace driver
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_IFS_H
diff --git a/lib/Driver/ToolChains/Linux.cpp b/lib/Driver/ToolChains/Linux.cpp
index d900508ad938..087783875ffe 100644
--- a/lib/Driver/ToolChains/Linux.cpp
+++ b/lib/Driver/ToolChains/Linux.cpp
@@ -658,11 +658,11 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
if (!DriverArgs.hasArg(options::OPT_nostdlibinc))
addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include");
- if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
- SmallString<128> P(D.ResourceDir);
- llvm::sys::path::append(P, "include");
- addSystemInclude(DriverArgs, CC1Args, P);
- }
+ SmallString<128> ResourceDirInclude(D.ResourceDir);
+ llvm::sys::path::append(ResourceDirInclude, "include");
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc) &&
+ (!getTriple().isMusl() || DriverArgs.hasArg(options::OPT_nostdlibinc)))
+ addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
if (DriverArgs.hasArg(options::OPT_nostdlibinc))
return;
@@ -860,6 +860,9 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include");
addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
+
+ if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && getTriple().isMusl())
+ addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
}
static std::string DetectLibcxxIncludePath(llvm::vfs::FileSystem &vfs,
@@ -1026,8 +1029,6 @@ SanitizerMask Linux::getSupportedSanitizers() const {
Res |= SanitizerKind::HWAddress;
Res |= SanitizerKind::KernelHWAddress;
}
- if (IsAArch64)
- Res |= SanitizerKind::MemTag;
return Res;
}
diff --git a/lib/Driver/ToolChains/MSP430.cpp b/lib/Driver/ToolChains/MSP430.cpp
index fc6048f17d78..bc77f015915d 100644
--- a/lib/Driver/ToolChains/MSP430.cpp
+++ b/lib/Driver/ToolChains/MSP430.cpp
@@ -227,6 +227,6 @@ void msp430::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
+ C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
CmdArgs, Inputs));
}
diff --git a/lib/Driver/ToolChains/MSVC.cpp b/lib/Driver/ToolChains/MSVC.cpp
index 6ed80a8f4752..1d31844bfcc8 100644
--- a/lib/Driver/ToolChains/MSVC.cpp
+++ b/lib/Driver/ToolChains/MSVC.cpp
@@ -331,6 +331,11 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
TC.getSubDirectoryPath(
toolchains::MSVCToolChain::SubDirectoryType::Lib)));
+ CmdArgs.push_back(Args.MakeArgString(
+ Twine("-libpath:") +
+ TC.getSubDirectoryPath(toolchains::MSVCToolChain::SubDirectoryType::Lib,
+ "atlmfc")));
+
if (TC.useUniversalCRT()) {
std::string UniversalCRTLibPath;
if (TC.getUniversalCRTLibraryPath(UniversalCRTLibPath))
@@ -548,7 +553,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
EnvVar.substr(0, PrefixLen) +
TC.getSubDirectoryPath(SubDirectoryType::Bin) +
llvm::Twine(llvm::sys::EnvPathSeparator) +
- TC.getSubDirectoryPath(SubDirectoryType::Bin, HostArch) +
+ TC.getSubDirectoryPath(SubDirectoryType::Bin, "", HostArch) +
(EnvVar.size() > PrefixLen
? llvm::Twine(llvm::sys::EnvPathSeparator) +
EnvVar.substr(PrefixLen)
@@ -565,7 +570,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA,
linkPath = TC.GetProgramPath(Linker.str().c_str());
}
- auto LinkCmd = llvm::make_unique<Command>(
+ auto LinkCmd = std::make_unique<Command>(
JA, *this, Args.MakeArgString(linkPath), CmdArgs, Inputs);
if (!Environment.empty())
LinkCmd->setEnvironment(Environment);
@@ -695,7 +700,7 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand(
CmdArgs.push_back(Fo);
std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe");
- return llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
+ return std::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
CmdArgs, Inputs);
}
@@ -824,6 +829,7 @@ static const char *llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch) {
// of hardcoding paths.
std::string
MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type,
+ llvm::StringRef SubdirParent,
llvm::Triple::ArchType TargetArch) const {
const char *SubdirName;
const char *IncludeName;
@@ -843,6 +849,9 @@ MSVCToolChain::getSubDirectoryPath(SubDirectoryType Type,
}
llvm::SmallString<256> Path(VCToolChainPath);
+ if (!SubdirParent.empty())
+ llvm::sys::path::append(Path, SubdirParent);
+
switch (Type) {
case SubDirectoryType::Bin:
if (VSLayout == ToolsetLayout::VS2017OrNewer) {
@@ -1228,6 +1237,8 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
if (!VCToolChainPath.empty()) {
addSystemInclude(DriverArgs, CC1Args,
getSubDirectoryPath(SubDirectoryType::Include));
+ addSystemInclude(DriverArgs, CC1Args,
+ getSubDirectoryPath(SubDirectoryType::Include, "atlmfc"));
if (useUniversalCRT()) {
std::string UniversalCRTSdkPath;
diff --git a/lib/Driver/ToolChains/MSVC.h b/lib/Driver/ToolChains/MSVC.h
index aba9417c9727..41a69a82fecf 100644
--- a/lib/Driver/ToolChains/MSVC.h
+++ b/lib/Driver/ToolChains/MSVC.h
@@ -78,10 +78,12 @@ public:
bool isPIEDefault() const override;
bool isPICDefaultForced() const override;
- /// Set CodeView as the default debug info format. Users can use -gcodeview
- /// and -gdwarf to override the default.
+ /// Set CodeView as the default debug info format for non-MachO binary
+ /// formats, and to DWARF otherwise. Users can use -gcodeview and -gdwarf to
+ /// override the default.
codegenoptions::DebugInfoFormat getDefaultDebugFormat() const override {
- return codegenoptions::DIF_CodeView;
+ return getTriple().isOSBinFormatMachO() ? codegenoptions::DIF_DWARF
+ : codegenoptions::DIF_CodeView;
}
/// Set the debugger tuning to "default", since we're definitely not tuning
@@ -96,12 +98,14 @@ public:
Lib,
};
std::string getSubDirectoryPath(SubDirectoryType Type,
+ llvm::StringRef SubdirParent,
llvm::Triple::ArchType TargetArch) const;
// Convenience overload.
// Uses the current target arch.
- std::string getSubDirectoryPath(SubDirectoryType Type) const {
- return getSubDirectoryPath(Type, getArch());
+ std::string getSubDirectoryPath(SubDirectoryType Type,
+ llvm::StringRef SubdirParent = "") const {
+ return getSubDirectoryPath(Type, SubdirParent, getArch());
}
enum class ToolsetLayout {
diff --git a/lib/Driver/ToolChains/MinGW.cpp b/lib/Driver/ToolChains/MinGW.cpp
index 0e1873cce25b..0d851114c225 100644
--- a/lib/Driver/ToolChains/MinGW.cpp
+++ b/lib/Driver/ToolChains/MinGW.cpp
@@ -49,7 +49,7 @@ void tools::MinGW::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
if (Args.hasArg(options::OPT_gsplit_dwarf))
SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output,
@@ -294,7 +294,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}
const char *Exec = Args.MakeArgString(TC.GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
// Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple.
diff --git a/lib/Driver/ToolChains/MinGW.h b/lib/Driver/ToolChains/MinGW.h
index 08298e910ebb..6752a405be87 100644
--- a/lib/Driver/ToolChains/MinGW.h
+++ b/lib/Driver/ToolChains/MinGW.h
@@ -34,7 +34,8 @@ public:
class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
public:
- Linker(const ToolChain &TC) : Tool("MinGW::Linker", "linker", TC) {}
+ Linker(const ToolChain &TC)
+ : Tool("MinGW::Linker", "linker", TC, Tool::RF_Full) {}
bool hasIntegratedCPP() const override { return false; }
bool isLinkJob() const override { return true; }
diff --git a/lib/Driver/ToolChains/Minix.cpp b/lib/Driver/ToolChains/Minix.cpp
index dbcc1f8908c4..6947049ea52e 100644
--- a/lib/Driver/ToolChains/Minix.cpp
+++ b/lib/Driver/ToolChains/Minix.cpp
@@ -36,7 +36,7 @@ void tools::minix::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void tools::minix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -88,7 +88,7 @@ void tools::minix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
/// Minix - Minix tool chain which can call as(1) and ld(1) directly.
diff --git a/lib/Driver/ToolChains/Myriad.cpp b/lib/Driver/ToolChains/Myriad.cpp
index 16eea1f13b14..2ce0f13ce3d1 100644
--- a/lib/Driver/ToolChains/Myriad.cpp
+++ b/lib/Driver/ToolChains/Myriad.cpp
@@ -77,7 +77,7 @@ void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA,
std::string Exec =
Args.MakeArgString(getToolChain().GetProgramPath("moviCompile"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
+ C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
CmdArgs, Inputs));
}
@@ -112,7 +112,7 @@ void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
std::string Exec =
Args.MakeArgString(getToolChain().GetProgramPath("moviAsm"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
+ C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
CmdArgs, Inputs));
}
@@ -198,7 +198,7 @@ void tools::Myriad::Linker::ConstructJob(Compilation &C, const JobAction &JA,
std::string Exec =
Args.MakeArgString(TC.GetProgramPath("sparc-myriad-rtems-ld"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
+ C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Exec),
CmdArgs, Inputs));
}
diff --git a/lib/Driver/ToolChains/NaCl.cpp b/lib/Driver/ToolChains/NaCl.cpp
index 984afc1758b1..97241c884027 100644
--- a/lib/Driver/ToolChains/NaCl.cpp
+++ b/lib/Driver/ToolChains/NaCl.cpp
@@ -193,7 +193,7 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
/// NaCl Toolchain
diff --git a/lib/Driver/ToolChains/NetBSD.cpp b/lib/Driver/ToolChains/NetBSD.cpp
index 3219a5d1e4f4..405142204199 100644
--- a/lib/Driver/ToolChains/NetBSD.cpp
+++ b/lib/Driver/ToolChains/NetBSD.cpp
@@ -103,7 +103,7 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString((getToolChain().GetProgramPath("as")));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -289,7 +289,11 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
- addOpenMPRuntime(CmdArgs, getToolChain(), Args);
+ // Use the static OpenMP runtime with -static-openmp
+ bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
+ !Args.hasArg(options::OPT_static);
+ addOpenMPRuntime(CmdArgs, getToolChain(), Args, StaticOpenMP);
+
if (D.CCCIsCXX()) {
if (ToolChain.ShouldLinkCXXStdlib(Args))
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
@@ -333,7 +337,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
ToolChain.addProfileRTLibs(Args, CmdArgs);
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
/// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly.
@@ -485,10 +489,23 @@ SanitizerMask NetBSD::getSupportedSanitizers() const {
return Res;
}
-void NetBSD::addClangTargetOptions(const ArgList &,
+void NetBSD::addClangTargetOptions(const ArgList &DriverArgs,
ArgStringList &CC1Args,
Action::OffloadKind) const {
const SanitizerArgs &SanArgs = getSanitizerArgs();
if (SanArgs.hasAnySanitizer())
CC1Args.push_back("-D_REENTRANT");
+
+ unsigned Major, Minor, Micro;
+ getTriple().getOSVersion(Major, Minor, Micro);
+ bool UseInitArrayDefault =
+ Major >= 9 || Major == 0 ||
+ getTriple().getArch() == llvm::Triple::aarch64 ||
+ getTriple().getArch() == llvm::Triple::aarch64_be ||
+ getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::armeb;
+
+ if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
+ options::OPT_fno_use_init_array, UseInitArrayDefault))
+ CC1Args.push_back("-fuse-init-array");
}
diff --git a/lib/Driver/ToolChains/OpenBSD.cpp b/lib/Driver/ToolChains/OpenBSD.cpp
index 8441b83c29a9..e93f5fcc3d81 100644
--- a/lib/Driver/ToolChains/OpenBSD.cpp
+++ b/lib/Driver/ToolChains/OpenBSD.cpp
@@ -89,7 +89,7 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -227,7 +227,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
SanitizerMask OpenBSD::getSupportedSanitizers() const {
diff --git a/lib/Driver/ToolChains/PPCLinux.cpp b/lib/Driver/ToolChains/PPCLinux.cpp
index 5221e5d0e22c..af2e3a21a0af 100644
--- a/lib/Driver/ToolChains/PPCLinux.cpp
+++ b/lib/Driver/ToolChains/PPCLinux.cpp
@@ -16,10 +16,7 @@ using namespace llvm::opt;
void PPCLinuxToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
- // PPC wrapper headers are implementation of x86 intrinsics on PowerPC, which
- // is not supported on PPC32 platform.
- if (getArch() != llvm::Triple::ppc &&
- !DriverArgs.hasArg(clang::driver::options::OPT_nostdinc) &&
+ if (!DriverArgs.hasArg(clang::driver::options::OPT_nostdinc) &&
!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
const Driver &D = getDriver();
SmallString<128> P(D.ResourceDir);
diff --git a/lib/Driver/ToolChains/PS4CPU.cpp b/lib/Driver/ToolChains/PS4CPU.cpp
index 7be471365668..4e8840296205 100644
--- a/lib/Driver/ToolChains/PS4CPU.cpp
+++ b/lib/Driver/ToolChains/PS4CPU.cpp
@@ -62,7 +62,7 @@ void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath("orbis-as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) {
@@ -141,7 +141,7 @@ static void ConstructPS4LinkJob(const Tool &T, Compilation &C,
const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld"));
- C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs));
}
static void ConstructGoldLinkJob(const Tool &T, Compilation &C,
@@ -319,7 +319,7 @@ static void ConstructGoldLinkJob(const Tool &T, Compilation &C,
Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld"));
#endif
- C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs));
}
void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA,
diff --git a/lib/Driver/ToolChains/RISCVToolchain.cpp b/lib/Driver/ToolChains/RISCVToolchain.cpp
index c5fdd129c3a8..22dc5117f196 100644
--- a/lib/Driver/ToolChains/RISCVToolchain.cpp
+++ b/lib/Driver/ToolChains/RISCVToolchain.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "RISCVToolchain.h"
+#include "Arch/RISCV.h"
#include "CommonArgs.h"
#include "InputInfo.h"
#include "clang/Driver/Compilation.h"
@@ -100,6 +101,12 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA,
std::string Linker = getToolChain().GetProgramPath(getShortName());
+ if (D.isUsingLTO()) {
+ assert(!Inputs.empty() && "Must have at least one input.");
+ AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0],
+ D.getLTOMode() == LTOK_Thin);
+ }
+
bool WantCRTs =
!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles);
@@ -134,7 +141,7 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
+ C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
CmdArgs, Inputs));
}
// RISCV tools end.
diff --git a/lib/Driver/ToolChains/RISCVToolchain.h b/lib/Driver/ToolChains/RISCVToolchain.h
index b2b56b066efd..673d749d76ff 100644
--- a/lib/Driver/ToolChains/RISCVToolchain.h
+++ b/lib/Driver/ToolChains/RISCVToolchain.h
@@ -25,6 +25,7 @@ public:
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind) const override;
+ bool HasNativeLLVMSupport() const override { return true; }
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
diff --git a/lib/Driver/ToolChains/Solaris.cpp b/lib/Driver/ToolChains/Solaris.cpp
index 38f24d4cf7e7..fc4e2cf151ef 100644
--- a/lib/Driver/ToolChains/Solaris.cpp
+++ b/lib/Driver/ToolChains/Solaris.cpp
@@ -8,6 +8,7 @@
#include "Solaris.h"
#include "CommonArgs.h"
+#include "clang/Basic/LangStandard.h"
#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
@@ -40,7 +41,7 @@ void solaris::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -86,8 +87,28 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
+
+ const Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi);
+ bool HaveAnsi = false;
+ const LangStandard *LangStd = nullptr;
+ if (Std) {
+ HaveAnsi = Std->getOption().matches(options::OPT_ansi);
+ if (!HaveAnsi)
+ LangStd = LangStandard::getLangStandardForName(Std->getValue());
+ }
+
+ const char *values_X = "values-Xa.o";
+ // Use values-Xc.o for -ansi, -std=c*, -std=iso9899:199409.
+ if (HaveAnsi || (LangStd && !LangStd->isGNUMode()))
+ values_X = "values-Xc.o";
+ CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(values_X)));
+
+ const char *values_xpg = "values-xpg6.o";
+ // Use values-xpg4.o for -std=c90, -std=gnu90, -std=iso9899:199409.
+ if (LangStd && LangStd->getLanguage() == Language::C && !LangStd->isC99())
+ values_xpg = "values-xpg4.o";
CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("values-Xa.o")));
+ Args.MakeArgString(getToolChain().GetFilePath(values_xpg)));
CmdArgs.push_back(
Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
}
@@ -129,7 +150,7 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().addProfileRTLibs(Args, CmdArgs);
const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
static StringRef getSolarisLibSuffix(const llvm::Triple &Triple) {
@@ -177,6 +198,7 @@ Solaris::Solaris(const Driver &D, const llvm::Triple &Triple,
SanitizerMask Solaris::getSupportedSanitizers() const {
const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
+ const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
SanitizerMask Res = ToolChain::getSupportedSanitizers();
// FIXME: Omit X86_64 until 64-bit support is figured out.
if (IsX86) {
@@ -184,6 +206,8 @@ SanitizerMask Solaris::getSupportedSanitizers() const {
Res |= SanitizerKind::PointerCompare;
Res |= SanitizerKind::PointerSubtract;
}
+ if (IsX86 || IsX86_64)
+ Res |= SanitizerKind::Function;
Res |= SanitizerKind::Vptr;
return Res;
}
diff --git a/lib/Driver/ToolChains/WebAssembly.cpp b/lib/Driver/ToolChains/WebAssembly.cpp
index 7a40c13c065a..3add913b700f 100644
--- a/lib/Driver/ToolChains/WebAssembly.cpp
+++ b/lib/Driver/ToolChains/WebAssembly.cpp
@@ -89,7 +89,7 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
- C.addCommand(llvm::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs));
}
WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple,
@@ -141,7 +141,7 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
options::OPT_fno_use_init_array, true))
CC1Args.push_back("-fuse-init-array");
- // '-pthread' implies atomics, bulk-memory, and mutable-globals
+ // '-pthread' implies atomics, bulk-memory, mutable-globals, and sign-ext
if (DriverArgs.hasFlag(options::OPT_pthread, options::OPT_no_pthread,
false)) {
if (DriverArgs.hasFlag(options::OPT_mno_atomics, options::OPT_matomics,
@@ -159,12 +159,39 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs,
getDriver().Diag(diag::err_drv_argument_not_allowed_with)
<< "-pthread"
<< "-mno-mutable-globals";
+ if (DriverArgs.hasFlag(options::OPT_mno_sign_ext, options::OPT_msign_ext,
+ false))
+ getDriver().Diag(diag::err_drv_argument_not_allowed_with)
+ << "-pthread"
+ << "-mno-sign-ext";
CC1Args.push_back("-target-feature");
CC1Args.push_back("+atomics");
CC1Args.push_back("-target-feature");
CC1Args.push_back("+bulk-memory");
CC1Args.push_back("-target-feature");
CC1Args.push_back("+mutable-globals");
+ CC1Args.push_back("-target-feature");
+ CC1Args.push_back("+sign-ext");
+ }
+
+ if (DriverArgs.getLastArg(options::OPT_fwasm_exceptions)) {
+ // '-fwasm-exceptions' is not compatible with '-mno-exception-handling'
+ if (DriverArgs.hasFlag(options::OPT_mno_exception_handing,
+ options::OPT_mexception_handing, false))
+ getDriver().Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fwasm-exceptions"
+ << "-mno-exception-handling";
+ // '-fwasm-exceptions' is not compatible with
+ // '-mllvm -enable-emscripten-cxx-exceptions'
+ for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) {
+ if (StringRef(A->getValue(0)) == "-enable-emscripten-cxx-exceptions")
+ getDriver().Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fwasm-exceptions"
+ << "-mllvm -enable-emscripten-cxx-exceptions";
+ }
+ // '-fwasm-exceptions' implies exception-handling
+ CC1Args.push_back("-target-feature");
+ CC1Args.push_back("+exception-handling");
}
}
diff --git a/lib/Driver/ToolChains/XCore.cpp b/lib/Driver/ToolChains/XCore.cpp
index 477cdb760914..ba3a6d44adda 100644
--- a/lib/Driver/ToolChains/XCore.cpp
+++ b/lib/Driver/ToolChains/XCore.cpp
@@ -52,7 +52,7 @@ void tools::XCore::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(II.getFilename());
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void tools::XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@@ -80,7 +80,7 @@ void tools::XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA,
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc"));
- C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
/// XCore tool chain
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 96937678ac6b..a30710645af3 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -7,24 +7,29 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Types.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Option/Arg.h"
#include <cassert>
-#include <string.h>
+#include <cstring>
using namespace clang::driver;
using namespace clang::driver::types;
struct TypeInfo {
const char *Name;
- const char *Flags;
const char *TempSuffix;
ID PreprocessedType;
+ const llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> Phases;
};
static const TypeInfo TypeInfos[] = {
-#define TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, FLAGS) \
- { NAME, FLAGS, TEMP_SUFFIX, TY_##PP_TYPE, },
+#define TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, ...) \
+ { NAME, TEMP_SUFFIX, TY_##PP_TYPE, { __VA_ARGS__ }, },
#include "clang/Driver/Types.def"
#undef TYPE
};
@@ -40,11 +45,19 @@ const char *types::getTypeName(ID Id) {
}
types::ID types::getPreprocessedType(ID Id) {
- return getInfo(Id).PreprocessedType;
+ ID PPT = getInfo(Id).PreprocessedType;
+ assert((llvm::is_contained(getInfo(Id).Phases, phases::Preprocess) !=
+ (PPT == TY_INVALID)) &&
+ "Unexpected Preprocess Type.");
+ return PPT;
+}
+
+static bool isPrepeocessedModuleType(ID Id) {
+ return Id == TY_CXXModule || Id == TY_PP_CXXModule;
}
types::ID types::getPrecompiledType(ID Id) {
- if (strchr(getInfo(Id).Flags, 'm'))
+ if (isPrepeocessedModuleType(Id))
return TY_ModuleFile;
if (onlyPrecompileType(Id))
return TY_PCH;
@@ -69,19 +82,31 @@ const char *types::getTypeTempSuffix(ID Id, bool CLMode) {
}
bool types::onlyAssembleType(ID Id) {
- return strchr(getInfo(Id).Flags, 'a');
+ return llvm::is_contained(getInfo(Id).Phases, phases::Assemble) &&
+ !llvm::is_contained(getInfo(Id).Phases, phases::Compile) &&
+ !llvm::is_contained(getInfo(Id).Phases, phases::Backend);
}
bool types::onlyPrecompileType(ID Id) {
- return strchr(getInfo(Id).Flags, 'p');
+ return llvm::is_contained(getInfo(Id).Phases, phases::Precompile) &&
+ !isPrepeocessedModuleType(Id);
}
bool types::canTypeBeUserSpecified(ID Id) {
- return strchr(getInfo(Id).Flags, 'u');
+ static const clang::driver::types::ID kStaticLangageTypes[] = {
+ TY_CUDA_DEVICE, TY_HIP_DEVICE, TY_PP_CHeader,
+ TY_PP_ObjCHeader, TY_PP_CXXHeader, TY_PP_ObjCXXHeader,
+ TY_PP_CXXModule, TY_LTO_IR, TY_LTO_BC,
+ TY_Plist, TY_RewrittenObjC, TY_RewrittenLegacyObjC,
+ TY_Remap, TY_PCH, TY_Object,
+ TY_Image, TY_dSYM, TY_Dependencies,
+ TY_CUDA_FATBIN, TY_HIP_FATBIN};
+ return !llvm::is_contained(kStaticLangageTypes, Id);
}
bool types::appendSuffixForType(ID Id) {
- return strchr(getInfo(Id).Flags, 'A');
+ return Id == TY_PCH || Id == TY_dSYM || Id == TY_CUDA_FATBIN ||
+ Id == TY_HIP_FATBIN;
}
bool types::canLipoType(ID Id) {
@@ -244,6 +269,7 @@ types::ID types::lookupTypeForExtension(llvm::StringRef Ext) {
.Case("lib", TY_Object)
.Case("mii", TY_PP_ObjCXX)
.Case("obj", TY_Object)
+ .Case("ifs", TY_IFS)
.Case("pch", TY_PCH)
.Case("pcm", TY_ModuleFile)
.Case("c++m", TY_CXXModule)
@@ -264,30 +290,77 @@ types::ID types::lookupTypeForTypeSpecifier(const char *Name) {
}
// FIXME: Why don't we just put this list in the defs file, eh.
+// FIXME: The list is now in Types.def but for now this function will verify
+// the old behavior and a subsequent change will delete most of the body.
void types::getCompilationPhases(ID Id, llvm::SmallVectorImpl<phases::ID> &P) {
- if (Id != TY_Object) {
- if (getPreprocessedType(Id) != TY_INVALID) {
- P.push_back(phases::Preprocess);
- }
-
- if (getPrecompiledType(Id) != TY_INVALID) {
- P.push_back(phases::Precompile);
- }
+ P = getInfo(Id).Phases;
+ assert(0 < P.size() && "Not enough phases in list");
+ assert(P.size() <= phases::MaxNumberOfPhases && "Too many phases in list");
+}
- if (!onlyPrecompileType(Id)) {
- if (!onlyAssembleType(Id)) {
- P.push_back(phases::Compile);
- P.push_back(phases::Backend);
- }
- P.push_back(phases::Assemble);
+void types::getCompilationPhases(const clang::driver::Driver &Driver,
+ llvm::opt::DerivedArgList &DAL, ID Id,
+ llvm::SmallVectorImpl<phases::ID> &P) {
+ llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PhaseList;
+ types::getCompilationPhases(Id, PhaseList);
+
+ // Filter to compiler mode. When the compiler is run as a preprocessor then
+ // compilation is not an option.
+ // -S runs the compiler in Assembly listing mode.
+ if (Driver.CCCIsCPP() || DAL.getLastArg(options::OPT_E) ||
+ DAL.getLastArg(options::OPT__SLASH_EP) ||
+ DAL.getLastArg(options::OPT_M, options::OPT_MM) ||
+ DAL.getLastArg(options::OPT__SLASH_P))
+ llvm::copy_if(PhaseList, std::back_inserter(P),
+ [](phases::ID Phase) { return Phase <= phases::Preprocess; });
+
+ // --precompile only runs up to precompilation.
+ // This is a clang extension and is not compatible with GCC.
+ else if (DAL.getLastArg(options::OPT__precompile))
+ llvm::copy_if(PhaseList, std::back_inserter(P),
+ [](phases::ID Phase) { return Phase <= phases::Precompile; });
+
+ // Treat Interface Stubs like its own compilation mode.
+ else if (DAL.getLastArg(options::OPT_emit_interface_stubs)) {
+ llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> IfsModePhaseList;
+ llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &PL = PhaseList;
+ phases::ID LastPhase = phases::IfsMerge;
+ if (Id != types::TY_IFS) {
+ if (DAL.hasArg(options::OPT_c))
+ LastPhase = phases::Compile;
+ PL = IfsModePhaseList;
+ types::getCompilationPhases(types::TY_IFS_CPP, PL);
}
+ llvm::copy_if(PL, std::back_inserter(P), [&](phases::ID Phase) {
+ return Phase <= LastPhase;
+ });
}
- if (!onlyPrecompileType(Id)) {
- P.push_back(phases::Link);
- }
- assert(0 < P.size() && "Not enough phases in list");
- assert(P.size() <= phases::MaxNumberOfPhases && "Too many phases in list");
+ // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler.
+ else if (DAL.getLastArg(options::OPT_fsyntax_only) ||
+ DAL.getLastArg(options::OPT_print_supported_cpus) ||
+ DAL.getLastArg(options::OPT_module_file_info) ||
+ DAL.getLastArg(options::OPT_verify_pch) ||
+ DAL.getLastArg(options::OPT_rewrite_objc) ||
+ DAL.getLastArg(options::OPT_rewrite_legacy_objc) ||
+ DAL.getLastArg(options::OPT__migrate) ||
+ DAL.getLastArg(options::OPT__analyze) ||
+ DAL.getLastArg(options::OPT_emit_ast))
+ llvm::copy_if(PhaseList, std::back_inserter(P),
+ [](phases::ID Phase) { return Phase <= phases::Compile; });
+
+ else if (DAL.getLastArg(options::OPT_S) ||
+ DAL.getLastArg(options::OPT_emit_llvm))
+ llvm::copy_if(PhaseList, std::back_inserter(P),
+ [](phases::ID Phase) { return Phase <= phases::Backend; });
+
+ else if (DAL.getLastArg(options::OPT_c))
+ llvm::copy_if(PhaseList, std::back_inserter(P),
+ [](phases::ID Phase) { return Phase <= phases::Assemble; });
+
+ // Generally means, do every phase until Link.
+ else
+ P = PhaseList;
}
ID types::lookupCXXTypeForCType(ID Id) {
diff --git a/lib/Driver/XRayArgs.cpp b/lib/Driver/XRayArgs.cpp
index 45ef96e12b3b..16e7c7ecf36b 100644
--- a/lib/Driver/XRayArgs.cpp
+++ b/lib/Driver/XRayArgs.cpp
@@ -52,7 +52,7 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) {
} else if (Triple.isOSFreeBSD() ||
Triple.isOSOpenBSD() ||
Triple.isOSNetBSD() ||
- Triple.getOS() == llvm::Triple::Darwin) {
+ Triple.isMacOSX()) {
if (Triple.getArch() != llvm::Triple::x86_64) {
D.Diag(diag::err_drv_clang_unsupported)
<< (std::string(XRayInstrumentOption) + " on " + Triple.str());
diff --git a/lib/Format/BreakableToken.cpp b/lib/Format/BreakableToken.cpp
index 72886ed00736..09ea5473c0c1 100644
--- a/lib/Format/BreakableToken.cpp
+++ b/lib/Format/BreakableToken.cpp
@@ -342,8 +342,8 @@ BreakableBlockComment::BreakableBlockComment(
StringRef TokenText(Tok.TokenText);
assert(TokenText.startswith("/*") && TokenText.endswith("*/"));
- TokenText.substr(2, TokenText.size() - 4).split(Lines,
- UseCRLF ? "\r\n" : "\n");
+ TokenText.substr(2, TokenText.size() - 4)
+ .split(Lines, UseCRLF ? "\r\n" : "\n");
int IndentDelta = StartColumn - OriginalStartColumn;
Content.resize(Lines.size());
@@ -456,10 +456,9 @@ BreakableBlockComment::BreakableBlockComment(
});
}
-BreakableToken::Split
-BreakableBlockComment::getSplit(unsigned LineIndex, unsigned TailOffset,
- unsigned ColumnLimit, unsigned ContentStartColumn,
- llvm::Regex &CommentPragmasRegex) const {
+BreakableToken::Split BreakableBlockComment::getSplit(
+ unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit,
+ unsigned ContentStartColumn, llvm::Regex &CommentPragmasRegex) const {
// Don't break lines matching the comment pragmas regex.
if (CommentPragmasRegex.match(Content[LineIndex]))
return Split(StringRef::npos, 0);
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index b04ede6fa939..2ff6e5ec2344 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -473,7 +473,10 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
}
// If the return type spans multiple lines, wrap before the function name.
- if ((Current.is(TT_FunctionDeclarationName) ||
+ if (((Current.is(TT_FunctionDeclarationName) &&
+ // Don't break before a C# function when no break after return type
+ (!Style.isCSharp() ||
+ Style.AlwaysBreakAfterReturnType != FormatStyle::RTBS_None)) ||
(Current.is(tok::kw_operator) && !Previous.is(tok::coloncolon))) &&
!Previous.is(tok::kw_template) && State.Stack.back().BreakBeforeParameter)
return true;
@@ -606,7 +609,9 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
// disallowing any further line breaks if there is no line break after the
// opening parenthesis. Don't break if it doesn't conserve columns.
if (Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak &&
- Previous.isOneOf(tok::l_paren, TT_TemplateOpener, tok::l_square) &&
+ (Previous.isOneOf(tok::l_paren, TT_TemplateOpener, tok::l_square) ||
+ (Previous.is(tok::l_brace) && Previous.BlockKind != BK_Block &&
+ Style.Cpp11BracedListStyle)) &&
State.Column > getNewLineColumn(State) &&
(!Previous.Previous || !Previous.Previous->isOneOf(
tok::kw_for, tok::kw_while, tok::kw_switch)) &&
@@ -676,8 +681,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
State.Column += Spaces;
if (Current.isNot(tok::comment) && Previous.is(tok::l_paren) &&
Previous.Previous &&
- (Previous.Previous->isOneOf(tok::kw_if, tok::kw_for) ||
- Previous.Previous->endsSequence(tok::kw_constexpr, tok::kw_if))) {
+ (Previous.Previous->is(tok::kw_for) || Previous.Previous->isIf())) {
// Treat the condition inside an if as if it was a second function
// parameter, i.e. let nested calls have a continuation indent.
State.Stack.back().LastSpace = State.Column;
@@ -930,6 +934,11 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
return std::max(State.Stack.back().LastSpace,
State.Stack.back().Indent + Style.ContinuationIndentWidth);
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths &&
+ State.Line->First->is(tok::kw_enum))
+ return (Style.IndentWidth * State.Line->First->IndentLevel) +
+ Style.IndentWidth;
+
if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block)
return Current.NestingLevel == 0 ? State.FirstIndent
: State.Stack.back().Indent;
@@ -1796,7 +1805,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current,
unsigned UnbreakableTailLength = (State.NextToken && canBreak(State))
? 0
: Current.UnbreakableTailLength;
- return llvm::make_unique<BreakableStringLiteral>(
+ return std::make_unique<BreakableStringLiteral>(
Current, StartColumn, Prefix, Postfix, UnbreakableTailLength,
State.Line->InPPDirective, Encoding, Style);
}
@@ -1808,7 +1817,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current,
switchesFormatting(Current)) {
return nullptr;
}
- return llvm::make_unique<BreakableBlockComment>(
+ return std::make_unique<BreakableBlockComment>(
Current, StartColumn, Current.OriginalColumn, !Current.Previous,
State.Line->InPPDirective, Encoding, Style, Whitespaces.useCRLF());
} else if (Current.is(TT_LineComment) &&
@@ -1818,7 +1827,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current,
CommentPragmasRegex.match(Current.TokenText.substr(2)) ||
switchesFormatting(Current))
return nullptr;
- return llvm::make_unique<BreakableLineCommentSection>(
+ return std::make_unique<BreakableLineCommentSection>(
Current, StartColumn, Current.OriginalColumn, !Current.Previous,
/*InPPDirective=*/false, Encoding, Style);
}
diff --git a/lib/Format/Encoding.h b/lib/Format/Encoding.h
index fe3d5f019858..a0d664121b2b 100644
--- a/lib/Format/Encoding.h
+++ b/lib/Format/Encoding.h
@@ -67,7 +67,8 @@ inline unsigned columnWidthWithTabs(StringRef Text, unsigned StartColumn,
if (TabPos == StringRef::npos)
return TotalWidth + columnWidth(Tail, Encoding);
TotalWidth += columnWidth(Tail.substr(0, TabPos), Encoding);
- TotalWidth += TabWidth - (TotalWidth + StartColumn) % TabWidth;
+ if (TabWidth)
+ TotalWidth += TabWidth - (TotalWidth + StartColumn) % TabWidth;
Tail = Tail.substr(TabPos + 1);
}
}
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index c48182976b04..cd44c0be85f0 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -67,10 +67,19 @@ template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
template <> struct ScalarEnumerationTraits<FormatStyle::LanguageStandard> {
static void enumeration(IO &IO, FormatStyle::LanguageStandard &Value) {
- IO.enumCase(Value, "Cpp03", FormatStyle::LS_Cpp03);
- IO.enumCase(Value, "C++03", FormatStyle::LS_Cpp03);
- IO.enumCase(Value, "Cpp11", FormatStyle::LS_Cpp11);
- IO.enumCase(Value, "C++11", FormatStyle::LS_Cpp11);
+ IO.enumCase(Value, "c++03", FormatStyle::LS_Cpp03);
+ IO.enumCase(Value, "C++03", FormatStyle::LS_Cpp03); // Legacy alias
+ IO.enumCase(Value, "Cpp03", FormatStyle::LS_Cpp03); // Legacy alias
+
+ IO.enumCase(Value, "c++11", FormatStyle::LS_Cpp11);
+ IO.enumCase(Value, "C++11", FormatStyle::LS_Cpp11); // Legacy alias
+
+ IO.enumCase(Value, "c++14", FormatStyle::LS_Cpp14);
+ IO.enumCase(Value, "c++17", FormatStyle::LS_Cpp17);
+ IO.enumCase(Value, "c++20", FormatStyle::LS_Cpp20);
+
+ IO.enumCase(Value, "Latest", FormatStyle::LS_Latest);
+ IO.enumCase(Value, "Cpp11", FormatStyle::LS_Latest); // Legacy alias
IO.enumCase(Value, "Auto", FormatStyle::LS_Auto);
}
};
@@ -95,6 +104,16 @@ template <> struct ScalarEnumerationTraits<FormatStyle::JavaScriptQuoteStyle> {
}
};
+template <> struct ScalarEnumerationTraits<FormatStyle::ShortBlockStyle> {
+ static void enumeration(IO &IO, FormatStyle::ShortBlockStyle &Value) {
+ IO.enumCase(Value, "Never", FormatStyle::SBS_Never);
+ IO.enumCase(Value, "false", FormatStyle::SBS_Never);
+ IO.enumCase(Value, "Always", FormatStyle::SBS_Always);
+ IO.enumCase(Value, "true", FormatStyle::SBS_Always);
+ IO.enumCase(Value, "Empty", FormatStyle::SBS_Empty);
+ }
+};
+
template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) {
IO.enumCase(Value, "None", FormatStyle::SFS_None);
@@ -155,6 +174,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
IO.enumCase(Value, "Mozilla", FormatStyle::BS_Mozilla);
IO.enumCase(Value, "Stroustrup", FormatStyle::BS_Stroustrup);
IO.enumCase(Value, "Allman", FormatStyle::BS_Allman);
+ IO.enumCase(Value, "Whitesmiths", FormatStyle::BS_Whitesmiths);
IO.enumCase(Value, "GNU", FormatStyle::BS_GNU);
IO.enumCase(Value, "WebKit", FormatStyle::BS_WebKit);
IO.enumCase(Value, "Custom", FormatStyle::BS_Custom);
@@ -162,6 +182,20 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
};
template <>
+struct ScalarEnumerationTraits<
+ FormatStyle::BraceWrappingAfterControlStatementStyle> {
+ static void
+ enumeration(IO &IO,
+ FormatStyle::BraceWrappingAfterControlStatementStyle &Value) {
+ IO.enumCase(Value, "false", FormatStyle::BWACS_Never);
+ IO.enumCase(Value, "true", FormatStyle::BWACS_Always);
+ IO.enumCase(Value, "Never", FormatStyle::BWACS_Never);
+ IO.enumCase(Value, "MultiLine", FormatStyle::BWACS_MultiLine);
+ IO.enumCase(Value, "Always", FormatStyle::BWACS_Always);
+ }
+};
+
+template <>
struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> {
static void
enumeration(IO &IO, FormatStyle::BreakConstructorInitializersStyle &Value) {
@@ -443,6 +477,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("IncludeCategories", Style.IncludeStyle.IncludeCategories);
IO.mapOptional("IncludeIsMainRegex", Style.IncludeStyle.IncludeIsMainRegex);
IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels);
+ IO.mapOptional("IndentGotoLabels", Style.IndentGotoLabels);
IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives);
IO.mapOptional("IndentWidth", Style.IndentWidth);
IO.mapOptional("IndentWrappedFunctionNames",
@@ -494,6 +529,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens);
IO.mapOptional("SpaceBeforeRangeBasedForLoopColon",
Style.SpaceBeforeRangeBasedForLoopColon);
+ IO.mapOptional("SpaceInEmptyBlock", Style.SpaceInEmptyBlock);
IO.mapOptional("SpaceInEmptyParentheses", Style.SpaceInEmptyParentheses);
IO.mapOptional("SpacesBeforeTrailingComments",
Style.SpacesBeforeTrailingComments);
@@ -607,9 +643,12 @@ static FormatStyle expandPresets(const FormatStyle &Style) {
if (Style.BreakBeforeBraces == FormatStyle::BS_Custom)
return Style;
FormatStyle Expanded = Style;
- Expanded.BraceWrapping = {false, false, false, false, false, false,
- false, false, false, false, false,
- false, false, true, true, true};
+ Expanded.BraceWrapping = {false, false, FormatStyle::BWACS_Never,
+ false, false, false,
+ false, false, false,
+ false, false, false,
+ false, true, true,
+ true};
switch (Style.BreakBeforeBraces) {
case FormatStyle::BS_Linux:
Expanded.BraceWrapping.AfterClass = true;
@@ -634,7 +673,21 @@ static FormatStyle expandPresets(const FormatStyle &Style) {
case FormatStyle::BS_Allman:
Expanded.BraceWrapping.AfterCaseLabel = true;
Expanded.BraceWrapping.AfterClass = true;
- Expanded.BraceWrapping.AfterControlStatement = true;
+ Expanded.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always;
+ Expanded.BraceWrapping.AfterEnum = true;
+ Expanded.BraceWrapping.AfterFunction = true;
+ Expanded.BraceWrapping.AfterNamespace = true;
+ Expanded.BraceWrapping.AfterObjCDeclaration = true;
+ Expanded.BraceWrapping.AfterStruct = true;
+ Expanded.BraceWrapping.AfterUnion = true;
+ Expanded.BraceWrapping.AfterExternBlock = true;
+ Expanded.BraceWrapping.BeforeCatch = true;
+ Expanded.BraceWrapping.BeforeElse = true;
+ break;
+ case FormatStyle::BS_Whitesmiths:
+ Expanded.BraceWrapping.AfterCaseLabel = true;
+ Expanded.BraceWrapping.AfterClass = true;
+ Expanded.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always;
Expanded.BraceWrapping.AfterEnum = true;
Expanded.BraceWrapping.AfterFunction = true;
Expanded.BraceWrapping.AfterNamespace = true;
@@ -645,8 +698,12 @@ static FormatStyle expandPresets(const FormatStyle &Style) {
Expanded.BraceWrapping.BeforeElse = true;
break;
case FormatStyle::BS_GNU:
- Expanded.BraceWrapping = {true, true, true, true, true, true, true, true,
- true, true, true, true, true, true, true, true};
+ Expanded.BraceWrapping = {true, true, FormatStyle::BWACS_Always,
+ true, true, true,
+ true, true, true,
+ true, true, true,
+ true, true, true,
+ true};
break;
case FormatStyle::BS_WebKit:
Expanded.BraceWrapping.AfterFunction = true;
@@ -672,7 +729,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.AllowAllConstructorInitializersOnNextLine = true;
LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
- LLVMStyle.AllowShortBlocksOnASingleLine = false;
+ LLVMStyle.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never;
LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;
LLVMStyle.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
LLVMStyle.AllowShortLambdasOnASingleLine = FormatStyle::SLS_All;
@@ -686,9 +743,12 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
LLVMStyle.BreakBeforeTernaryOperators = true;
LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
- LLVMStyle.BraceWrapping = {false, false, false, false, false, false,
- false, false, false, false, false,
- false, false, true, true, true};
+ LLVMStyle.BraceWrapping = {false, false, FormatStyle::BWACS_Never,
+ false, false, false,
+ false, false, false,
+ false, false, false,
+ false, true, true,
+ true};
LLVMStyle.BreakAfterJavaFieldAnnotations = false;
LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon;
@@ -707,12 +767,13 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.ForEachMacros.push_back("Q_FOREACH");
LLVMStyle.ForEachMacros.push_back("BOOST_FOREACH");
LLVMStyle.IncludeStyle.IncludeCategories = {
- {"^\"(llvm|llvm-c|clang|clang-c)/", 2},
- {"^(<|\"(gtest|gmock|isl|json)/)", 3},
- {".*", 1}};
+ {"^\"(llvm|llvm-c|clang|clang-c)/", 2, 0},
+ {"^(<|\"(gtest|gmock|isl|json)/)", 3, 0},
+ {".*", 1, 0}};
LLVMStyle.IncludeStyle.IncludeIsMainRegex = "(Test)?$";
LLVMStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Preserve;
LLVMStyle.IndentCaseLabels = false;
+ LLVMStyle.IndentGotoLabels = true;
LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None;
LLVMStyle.IndentWrappedFunctionNames = false;
LLVMStyle.IndentWidth = 2;
@@ -728,11 +789,12 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.ObjCSpaceBeforeProtocolList = true;
LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
LLVMStyle.SpacesBeforeTrailingComments = 1;
- LLVMStyle.Standard = FormatStyle::LS_Cpp11;
+ LLVMStyle.Standard = FormatStyle::LS_Latest;
LLVMStyle.UseTab = FormatStyle::UT_Never;
LLVMStyle.ReflowComments = true;
LLVMStyle.SpacesInParentheses = false;
LLVMStyle.SpacesInSquareBrackets = false;
+ LLVMStyle.SpaceInEmptyBlock = false;
LLVMStyle.SpaceInEmptyParentheses = false;
LLVMStyle.SpacesInContainerLiterals = true;
LLVMStyle.SpacesInCStyleCastParentheses = false;
@@ -789,8 +851,10 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
GoogleStyle.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes;
GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
GoogleStyle.DerivePointerAlignment = true;
- GoogleStyle.IncludeStyle.IncludeCategories = {
- {"^<ext/.*\\.h>", 2}, {"^<.*\\.h>", 1}, {"^<.*", 2}, {".*", 3}};
+ GoogleStyle.IncludeStyle.IncludeCategories = {{"^<ext/.*\\.h>", 2, 0},
+ {"^<.*\\.h>", 1, 0},
+ {"^<.*", 2, 0},
+ {".*", 3, 0}};
GoogleStyle.IncludeStyle.IncludeIsMainRegex = "([-_](test|unittest))?$";
GoogleStyle.IncludeStyle.IncludeBlocks = tooling::IncludeStyle::IBS_Regroup;
GoogleStyle.IndentCaseLabels = true;
@@ -897,6 +961,27 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
FormatStyle ChromiumStyle = getGoogleStyle(Language);
+
+ // Disable include reordering across blocks in Chromium code.
+ // - clang-format tries to detect that foo.h is the "main" header for
+ // foo.cc and foo_unittest.cc via IncludeIsMainRegex. However, Chromium
+ // uses many other suffices (_win.cc, _mac.mm, _posix.cc, _browsertest.cc,
+ // _private.cc, _impl.cc etc) in different permutations
+ // (_win_browsertest.cc) so disable this until IncludeIsMainRegex has a
+ // better default for Chromium code.
+ // - The default for .cc and .mm files is different (r357695) for Google style
+ // for the same reason. The plan is to unify this again once the main
+ // header detection works for Google's ObjC code, but this hasn't happened
+ // yet. Since Chromium has some ObjC code, switching Chromium is blocked
+ // on that.
+ // - Finally, "If include reordering is harmful, put things in different
+ // blocks to prevent it" has been a recommendation for a long time that
+ // people are used to. We'll need a dev education push to change this to
+ // "If include reordering is harmful, put things in a different block and
+ // _prepend that with a comment_ to prevent it" before changing behavior.
+ ChromiumStyle.IncludeStyle.IncludeBlocks =
+ tooling::IncludeStyle::IBS_Preserve;
+
if (Language == FormatStyle::LK_Java) {
ChromiumStyle.AllowShortIfStatementsOnASingleLine =
FormatStyle::SIS_WithoutElse;
@@ -966,6 +1051,7 @@ FormatStyle getWebKitStyle() {
Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
Style.AlignOperands = false;
Style.AlignTrailingComments = false;
+ Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;
Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
Style.BreakBeforeBraces = FormatStyle::BS_WebKit;
Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma;
@@ -978,6 +1064,7 @@ FormatStyle getWebKitStyle() {
Style.ObjCSpaceAfterProperty = true;
Style.PointerAlignment = FormatStyle::PAS_Left;
Style.SpaceBeforeCpp11BracedList = true;
+ Style.SpaceInEmptyBlock = true;
return Style;
}
@@ -997,14 +1084,14 @@ FormatStyle getGNUStyle() {
}
FormatStyle getMicrosoftStyle(FormatStyle::LanguageKind Language) {
- FormatStyle Style = getLLVMStyle();
+ FormatStyle Style = getLLVMStyle(Language);
Style.ColumnLimit = 120;
Style.TabWidth = 4;
Style.IndentWidth = 4;
Style.UseTab = FormatStyle::UT_Never;
Style.BreakBeforeBraces = FormatStyle::BS_Custom;
Style.BraceWrapping.AfterClass = true;
- Style.BraceWrapping.AfterControlStatement = true;
+ Style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always;
Style.BraceWrapping.AfterEnum = true;
Style.BraceWrapping.AfterFunction = true;
Style.BraceWrapping.AfterNamespace = true;
@@ -1015,10 +1102,11 @@ FormatStyle getMicrosoftStyle(FormatStyle::LanguageKind Language) {
Style.BraceWrapping.BeforeElse = true;
Style.PenaltyReturnTypeOnItsOwnLine = 1000;
Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
- Style.AllowShortBlocksOnASingleLine = false;
Style.AllowShortCaseLabelsOnASingleLine = false;
Style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never;
Style.AllowShortLoopsOnASingleLine = false;
+ Style.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None;
+ Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
return Style;
}
@@ -1346,7 +1434,7 @@ private:
: FormatStyle::PAS_Right;
if (Style.Standard == FormatStyle::LS_Auto)
Style.Standard = hasCpp03IncompatibleFormat(AnnotatedLines)
- ? FormatStyle::LS_Cpp11
+ ? FormatStyle::LS_Latest
: FormatStyle::LS_Cpp03;
BinPackInconclusiveFunctions =
HasBinPackedFunction || !HasOnePerLineFunction;
@@ -1380,22 +1468,29 @@ public:
checkEmptyNamespace(AnnotatedLines);
- for (auto &Line : AnnotatedLines) {
- if (Line->Affected) {
- cleanupRight(Line->First, tok::comma, tok::comma);
- cleanupRight(Line->First, TT_CtorInitializerColon, tok::comma);
- cleanupRight(Line->First, tok::l_paren, tok::comma);
- cleanupLeft(Line->First, tok::comma, tok::r_paren);
- cleanupLeft(Line->First, TT_CtorInitializerComma, tok::l_brace);
- cleanupLeft(Line->First, TT_CtorInitializerColon, tok::l_brace);
- cleanupLeft(Line->First, TT_CtorInitializerColon, tok::equal);
- }
- }
+ for (auto *Line : AnnotatedLines)
+ cleanupLine(Line);
return {generateFixes(), 0};
}
private:
+ void cleanupLine(AnnotatedLine *Line) {
+ for (auto *Child : Line->Children) {
+ cleanupLine(Child);
+ }
+
+ if (Line->Affected) {
+ cleanupRight(Line->First, tok::comma, tok::comma);
+ cleanupRight(Line->First, TT_CtorInitializerColon, tok::comma);
+ cleanupRight(Line->First, tok::l_paren, tok::comma);
+ cleanupLeft(Line->First, tok::comma, tok::r_paren);
+ cleanupLeft(Line->First, TT_CtorInitializerComma, tok::l_brace);
+ cleanupLeft(Line->First, TT_CtorInitializerColon, tok::l_brace);
+ cleanupLeft(Line->First, TT_CtorInitializerColon, tok::equal);
+ }
+ }
+
bool containsOnlyComments(const AnnotatedLine &Line) {
for (FormatToken *Tok = Line.First; Tok != nullptr; Tok = Tok->Next) {
if (Tok->isNot(tok::comment))
@@ -1685,10 +1780,11 @@ private:
std::end(FoundationIdentifiers),
FormatTok->TokenText)) ||
FormatTok->is(TT_ObjCStringLiteral) ||
- FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS,
- TT_ObjCBlockLBrace, TT_ObjCBlockLParen,
- TT_ObjCDecl, TT_ObjCForIn, TT_ObjCMethodExpr,
- TT_ObjCMethodSpecifier, TT_ObjCProperty)) {
+ FormatTok->isOneOf(Keywords.kw_NS_CLOSED_ENUM, Keywords.kw_NS_ENUM,
+ Keywords.kw_NS_OPTIONS, TT_ObjCBlockLBrace,
+ TT_ObjCBlockLParen, TT_ObjCDecl, TT_ObjCForIn,
+ TT_ObjCMethodExpr, TT_ObjCMethodSpecifier,
+ TT_ObjCProperty)) {
LLVM_DEBUG(llvm::dbgs()
<< "Detected ObjC at location "
<< FormatTok->Tok.getLocation().printToString(
@@ -1712,6 +1808,7 @@ struct IncludeDirective {
StringRef Text;
unsigned Offset;
int Category;
+ int Priority;
};
struct JavaImportDirective {
@@ -1763,6 +1860,28 @@ FindCursorIndex(const SmallVectorImpl<IncludeDirective> &Includes,
return std::make_pair(CursorIndex, OffsetToEOL);
}
+// Replace all "\r\n" with "\n".
+std::string replaceCRLF(const std::string &Code) {
+ std::string NewCode;
+ size_t Pos = 0, LastPos = 0;
+
+ do {
+ Pos = Code.find("\r\n", LastPos);
+ if (Pos == LastPos) {
+ LastPos++;
+ continue;
+ }
+ if (Pos == std::string::npos) {
+ NewCode += Code.substr(LastPos);
+ break;
+ }
+ NewCode += Code.substr(LastPos, Pos - LastPos) + "\n";
+ LastPos = Pos + 2;
+ } while (Pos != std::string::npos);
+
+ return NewCode;
+}
+
// Sorts and deduplicate a block of includes given by 'Includes' alphabetically
// adding the necessary replacement to 'Replaces'. 'Includes' must be in strict
// source order.
@@ -1773,8 +1892,9 @@ FindCursorIndex(const SmallVectorImpl<IncludeDirective> &Includes,
static void sortCppIncludes(const FormatStyle &Style,
const SmallVectorImpl<IncludeDirective> &Includes,
ArrayRef<tooling::Range> Ranges, StringRef FileName,
- StringRef Code,
- tooling::Replacements &Replaces, unsigned *Cursor) {
+ StringRef Code, tooling::Replacements &Replaces,
+ unsigned *Cursor) {
+ tooling::IncludeCategoryManager Categories(Style.IncludeStyle, FileName);
unsigned IncludesBeginOffset = Includes.front().Offset;
unsigned IncludesEndOffset =
Includes.back().Offset + Includes.back().Text.size();
@@ -1782,11 +1902,12 @@ static void sortCppIncludes(const FormatStyle &Style,
if (!affectsRange(Ranges, IncludesBeginOffset, IncludesEndOffset))
return;
SmallVector<unsigned, 16> Indices;
- for (unsigned i = 0, e = Includes.size(); i != e; ++i)
+ for (unsigned i = 0, e = Includes.size(); i != e; ++i) {
Indices.push_back(i);
+ }
llvm::stable_sort(Indices, [&](unsigned LHSI, unsigned RHSI) {
- return std::tie(Includes[LHSI].Category, Includes[LHSI].Filename) <
- std::tie(Includes[RHSI].Category, Includes[RHSI].Filename);
+ return std::tie(Includes[LHSI].Priority, Includes[LHSI].Filename) <
+ std::tie(Includes[RHSI].Priority, Includes[RHSI].Filename);
});
// The index of the include on which the cursor will be put after
// sorting/deduplicating.
@@ -1834,7 +1955,8 @@ static void sortCppIncludes(const FormatStyle &Style,
// If the #includes are out of order, we generate a single replacement fixing
// the entire range of blocks. Otherwise, no replacement is generated.
- if (result == Code.substr(IncludesBeginOffset, IncludesBlockSize))
+ if (replaceCRLF(result) ==
+ replaceCRLF(Code.substr(IncludesBeginOffset, IncludesBlockSize)))
return;
auto Err = Replaces.add(tooling::Replacement(
@@ -1901,9 +2023,12 @@ tooling::Replacements sortCppIncludes(const FormatStyle &Style, StringRef Code,
int Category = Categories.getIncludePriority(
IncludeName,
/*CheckMainHeader=*/!MainIncludeFound && FirstIncludeBlock);
+ int Priority = Categories.getSortIncludePriority(
+ IncludeName, !MainIncludeFound && FirstIncludeBlock);
if (Category == 0)
MainIncludeFound = true;
- IncludesInBlock.push_back({IncludeName, Line, Prev, Category});
+ IncludesInBlock.push_back(
+ {IncludeName, Line, Prev, Category, Priority});
} else if (!IncludesInBlock.empty() && !EmptyLineSkipped) {
sortCppIncludes(Style, IncludesInBlock, Ranges, FileName, Code,
Replaces, Cursor);
@@ -1999,7 +2124,8 @@ static void sortJavaImports(const FormatStyle &Style,
// If the imports are out of order, we generate a single replacement fixing
// the entire block. Otherwise, no replacement is generated.
- if (result == Code.substr(Imports.front().Offset, ImportsBlockSize))
+ if (replaceCRLF(result) ==
+ replaceCRLF(Code.substr(Imports.front().Offset, ImportsBlockSize)))
return;
auto Err = Replaces.add(tooling::Replacement(FileName, Imports.front().Offset,
@@ -2288,8 +2414,8 @@ reformat(const FormatStyle &Style, StringRef Code,
});
auto Env =
- llvm::make_unique<Environment>(Code, FileName, Ranges, FirstStartColumn,
- NextStartColumn, LastStartColumn);
+ std::make_unique<Environment>(Code, FileName, Ranges, FirstStartColumn,
+ NextStartColumn, LastStartColumn);
llvm::Optional<std::string> CurrentCode = None;
tooling::Replacements Fixes;
unsigned Penalty = 0;
@@ -2302,7 +2428,7 @@ reformat(const FormatStyle &Style, StringRef Code,
Penalty += PassFixes.second;
if (I + 1 < E) {
CurrentCode = std::move(*NewCode);
- Env = llvm::make_unique<Environment>(
+ Env = std::make_unique<Environment>(
*CurrentCode, FileName,
tooling::calculateRangesAfterReplacements(Fixes, Ranges),
FirstStartColumn, NextStartColumn, LastStartColumn);
@@ -2364,11 +2490,18 @@ tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
LangOptions getFormattingLangOpts(const FormatStyle &Style) {
LangOptions LangOpts;
+
+ FormatStyle::LanguageStandard LexingStd = Style.Standard;
+ if (LexingStd == FormatStyle::LS_Auto)
+ LexingStd = FormatStyle::LS_Latest;
+ if (LexingStd == FormatStyle::LS_Latest)
+ LexingStd = FormatStyle::LS_Cpp20;
LangOpts.CPlusPlus = 1;
- LangOpts.CPlusPlus11 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
- LangOpts.CPlusPlus14 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
- LangOpts.CPlusPlus17 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
- LangOpts.CPlusPlus2a = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
+ LangOpts.CPlusPlus11 = LexingStd >= FormatStyle::LS_Cpp11;
+ LangOpts.CPlusPlus14 = LexingStd >= FormatStyle::LS_Cpp14;
+ LangOpts.CPlusPlus17 = LexingStd >= FormatStyle::LS_Cpp17;
+ LangOpts.CPlusPlus2a = LexingStd >= FormatStyle::LS_Cpp20;
+
LangOpts.LineComment = 1;
bool AlternativeOperators = Style.isCpp();
LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
@@ -2393,8 +2526,9 @@ const char *StyleOptionHelpDescription =
static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
if (FileName.endswith(".java"))
return FormatStyle::LK_Java;
- if (FileName.endswith_lower(".js") || FileName.endswith_lower(".ts"))
- return FormatStyle::LK_JavaScript; // JavaScript or TypeScript.
+ if (FileName.endswith_lower(".js") || FileName.endswith_lower(".mjs") ||
+ FileName.endswith_lower(".ts"))
+ return FormatStyle::LK_JavaScript; // (module) JavaScript or TypeScript.
if (FileName.endswith(".m") || FileName.endswith(".mm"))
return FormatStyle::LK_ObjC;
if (FileName.endswith_lower(".proto") ||
diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h
index df7493742025..b11f36559a8b 100644
--- a/lib/Format/FormatToken.h
+++ b/lib/Format/FormatToken.h
@@ -327,6 +327,11 @@ struct FormatToken {
}
template <typename T> bool isNot(T Kind) const { return !is(Kind); }
+ bool isIf(bool AllowConstexprMacro = true) const {
+ return is(tok::kw_if) || endsSequence(tok::kw_constexpr, tok::kw_if) ||
+ (endsSequence(tok::identifier, tok::kw_if) && AllowConstexprMacro);
+ }
+
bool closesScopeAfterBlock() const {
if (BlockKind == BK_Block)
return true;
@@ -344,6 +349,10 @@ struct FormatToken {
/// \c true if this token ends a sequence with the given tokens in order,
/// following the ``Previous`` pointers, ignoring comments.
+ /// For example, given tokens [T1, T2, T3], the function returns true if
+ /// 3 tokens ending at this (ignoring comments) are [T3, T2, T1]. In other
+ /// words, the tokens passed to this function need to the reverse of the
+ /// order the tokens appear in code.
template <typename A, typename... Ts>
bool endsSequence(A K1, Ts... Tokens) const {
return endsSequenceInternal(K1, Tokens...);
@@ -677,8 +686,10 @@ struct AdditionalKeywords {
kw_override = &IdentTable.get("override");
kw_in = &IdentTable.get("in");
kw_of = &IdentTable.get("of");
+ kw_CF_CLOSED_ENUM = &IdentTable.get("CF_CLOSED_ENUM");
kw_CF_ENUM = &IdentTable.get("CF_ENUM");
kw_CF_OPTIONS = &IdentTable.get("CF_OPTIONS");
+ kw_NS_CLOSED_ENUM = &IdentTable.get("NS_CLOSED_ENUM");
kw_NS_ENUM = &IdentTable.get("NS_ENUM");
kw_NS_OPTIONS = &IdentTable.get("NS_OPTIONS");
@@ -787,8 +798,10 @@ struct AdditionalKeywords {
IdentifierInfo *kw_override;
IdentifierInfo *kw_in;
IdentifierInfo *kw_of;
+ IdentifierInfo *kw_CF_CLOSED_ENUM;
IdentifierInfo *kw_CF_ENUM;
IdentifierInfo *kw_CF_OPTIONS;
+ IdentifierInfo *kw_NS_CLOSED_ENUM;
IdentifierInfo *kw_NS_ENUM;
IdentifierInfo *kw_NS_OPTIONS;
IdentifierInfo *kw___except;
diff --git a/lib/Format/FormatTokenLexer.cpp b/lib/Format/FormatTokenLexer.cpp
index 009b8849753c..5d8a77577c0b 100644
--- a/lib/Format/FormatTokenLexer.cpp
+++ b/lib/Format/FormatTokenLexer.cpp
@@ -80,6 +80,8 @@ void FormatTokenLexer::tryMergePreviousTokens() {
return;
if (tryMergeCSharpNullConditionals())
return;
+ if (tryTransformCSharpForEach())
+ return;
static const tok::TokenKind JSRightArrow[] = {tok::equal, tok::greater};
if (tryMergeTokens(JSRightArrow, TT_JsFatArrow))
return;
@@ -254,6 +256,21 @@ bool FormatTokenLexer::tryMergeCSharpNullConditionals() {
return true;
}
+// In C# transform identifier foreach into kw_foreach
+bool FormatTokenLexer::tryTransformCSharpForEach() {
+ if (Tokens.size() < 1)
+ return false;
+ auto &Identifier = *(Tokens.end() - 1);
+ if (!Identifier->is(tok::identifier))
+ return false;
+ if (Identifier->TokenText != "foreach")
+ return false;
+
+ Identifier->Type = TT_ForEachMacro;
+ Identifier->Tok.setKind(tok::kw_for);
+ return true;
+}
+
bool FormatTokenLexer::tryMergeLessLess() {
// Merge X,less,less,Y into X,lessless,Y unless X or Y is less.
if (Tokens.size() < 3)
@@ -657,7 +674,8 @@ FormatToken *FormatTokenLexer::getNextToken() {
++Column;
break;
case '\t':
- Column += Style.TabWidth - Column % Style.TabWidth;
+ Column +=
+ Style.TabWidth - (Style.TabWidth ? Column % Style.TabWidth : 0);
break;
case '\\':
if (i + 1 == e || (Text[i + 1] != '\r' && Text[i + 1] != '\n'))
diff --git a/lib/Format/FormatTokenLexer.h b/lib/Format/FormatTokenLexer.h
index 1e096fc50205..611211be055a 100644
--- a/lib/Format/FormatTokenLexer.h
+++ b/lib/Format/FormatTokenLexer.h
@@ -53,6 +53,7 @@ private:
bool tryMergeCSharpKeywordVariables();
bool tryMergeCSharpNullConditionals();
bool tryMergeCSharpDoubleQuestion();
+ bool tryTransformCSharpForEach();
bool tryMergeTokens(ArrayRef<tok::TokenKind> Kinds, TokenType NewType);
diff --git a/lib/Format/NamespaceEndCommentsFixer.cpp b/lib/Format/NamespaceEndCommentsFixer.cpp
index d04fc8f115fb..98901cff2681 100644
--- a/lib/Format/NamespaceEndCommentsFixer.cpp
+++ b/lib/Format/NamespaceEndCommentsFixer.cpp
@@ -36,7 +36,7 @@ std::string computeName(const FormatToken *NamespaceTok) {
const FormatToken *Tok = NamespaceTok->getNextNonComment();
if (NamespaceTok->is(TT_NamespaceMacro)) {
// Collects all the non-comment tokens between opening parenthesis
- // and closing parenthesis or comma
+ // and closing parenthesis or comma.
assert(Tok && Tok->is(tok::l_paren) && "expected an opening parenthesis");
Tok = Tok->getNextNonComment();
while (Tok && !Tok->isOneOf(tok::r_paren, tok::comma)) {
@@ -44,9 +44,21 @@ std::string computeName(const FormatToken *NamespaceTok) {
Tok = Tok->getNextNonComment();
}
} else {
- // Collects all the non-comment tokens between 'namespace' and '{'.
+ // For `namespace [[foo]] A::B::inline C {` or
+ // `namespace MACRO1 MACRO2 A::B::inline C {`, returns "A::B::inline C".
+ // Peek for the first '::' (or '{') and then return all tokens from one
+ // token before that up until the '{'.
+ const FormatToken *FirstNSTok = Tok;
+ while (Tok && !Tok->is(tok::l_brace) && !Tok->is(tok::coloncolon)) {
+ FirstNSTok = Tok;
+ Tok = Tok->getNextNonComment();
+ }
+
+ Tok = FirstNSTok;
while (Tok && !Tok->is(tok::l_brace)) {
name += Tok->TokenText;
+ if (Tok->is(tok::kw_inline))
+ name += " ";
Tok = Tok->getNextNonComment();
}
}
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 490c4f46135e..1ed35597d075 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -15,6 +15,7 @@
#include "TokenAnnotator.h"
#include "FormatToken.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TokenKinds.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/Debug.h"
@@ -40,6 +41,21 @@ static bool canBeObjCSelectorComponent(const FormatToken &Tok) {
return Tok.Tok.getIdentifierInfo() != nullptr;
}
+/// With `Left` being '(', check if we're at either `[...](` or
+/// `[...]<...>(`, where the [ opens a lambda capture list.
+static bool isLambdaParameterList(const FormatToken *Left) {
+ // Skip <...> if present.
+ if (Left->Previous && Left->Previous->is(tok::greater) &&
+ Left->Previous->MatchingParen &&
+ Left->Previous->MatchingParen->is(TT_TemplateOpener))
+ Left = Left->Previous->MatchingParen;
+
+ // Check for `[...]`.
+ return Left->Previous && Left->Previous->is(tok::r_square) &&
+ Left->Previous->MatchingParen &&
+ Left->Previous->MatchingParen->is(TT_LambdaLSquare);
+}
+
/// A parser that gathers additional information about tokens.
///
/// The \c TokenAnnotator tries to match parenthesis and square brakets and
@@ -175,9 +191,9 @@ private:
Contexts.back().IsExpression = false;
} else if (Left->Previous &&
(Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_decltype,
- tok::kw_if, tok::kw_while, tok::l_paren,
+ tok::kw_while, tok::l_paren,
tok::comma) ||
- Left->Previous->endsSequence(tok::kw_constexpr, tok::kw_if) ||
+ Left->Previous->isIf() ||
Left->Previous->is(TT_BinaryOperator))) {
// static_assert, if and while usually contain expressions.
Contexts.back().IsExpression = true;
@@ -191,9 +207,7 @@ private:
Left->Previous->is(TT_JsTypeColon)) {
// let x: (SomeType);
Contexts.back().IsExpression = false;
- } else if (Left->Previous && Left->Previous->is(tok::r_square) &&
- Left->Previous->MatchingParen &&
- Left->Previous->MatchingParen->is(TT_LambdaLSquare)) {
+ } else if (isLambdaParameterList(Left)) {
// This is a parameter list of a lambda expression.
Contexts.back().IsExpression = false;
} else if (Line.InPPDirective &&
@@ -382,6 +396,12 @@ private:
Keywords.kw_internal)) {
return true;
}
+
+ // incase its a [XXX] retval func(....
+ if (AttrTok->Next &&
+ AttrTok->Next->startsSequence(tok::identifier, tok::l_paren))
+ return true;
+
return false;
}
@@ -476,6 +496,8 @@ private:
} else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace &&
Parent && Parent->isOneOf(tok::l_brace, tok::comma)) {
Left->Type = TT_DesignatedInitializerLSquare;
+ } else if (IsCSharp11AttributeSpecifier) {
+ Left->Type = TT_AttributeSquare;
} else if (CurrentToken->is(tok::r_square) && Parent &&
Parent->is(TT_TemplateCloser)) {
Left->Type = TT_ArraySubscriptLSquare;
@@ -523,8 +545,6 @@ private:
// Should only be relevant to JavaScript:
tok::kw_default)) {
Left->Type = TT_ArrayInitializerLSquare;
- } else if (IsCSharp11AttributeSpecifier) {
- Left->Type = TT_AttributeSquare;
} else {
BindingIncrease = 10;
Left->Type = TT_ArraySubscriptLSquare;
@@ -826,7 +846,7 @@ private:
case tok::kw_if:
case tok::kw_while:
if (Tok->is(tok::kw_if) && CurrentToken &&
- CurrentToken->is(tok::kw_constexpr))
+ CurrentToken->isOneOf(tok::kw_constexpr, tok::identifier))
next();
if (CurrentToken && CurrentToken->is(tok::l_paren)) {
next();
@@ -918,6 +938,8 @@ private:
case tok::greater:
if (Style.Language != FormatStyle::LK_TextProto)
Tok->Type = TT_BinaryOperator;
+ if (Tok->Previous && Tok->Previous->is(TT_TemplateCloser))
+ Tok->SpacesRequiredBefore = 1;
break;
case tok::kw_operator:
if (Style.Language == FormatStyle::LK_TextProto ||
@@ -1078,6 +1100,7 @@ private:
case tok::pp_if:
case tok::pp_elif:
Contexts.back().IsExpression = true;
+ next();
parseLine();
break;
default:
@@ -1097,6 +1120,8 @@ private:
public:
LineType parseLine() {
+ if (!CurrentToken)
+ return LT_Invalid;
NonTemplateLess.clear();
if (CurrentToken->is(tok::hash))
return parsePreprocessorDirective();
@@ -1368,7 +1393,9 @@ private:
Style.Language == FormatStyle::LK_Java) {
Current.Type = TT_LambdaArrow;
} else if (Current.is(tok::arrow) && AutoFound && Line.MustBeDeclaration &&
- Current.NestingLevel == 0) {
+ Current.NestingLevel == 0 &&
+ !Current.Previous->is(tok::kw_operator)) {
+ // not auto operator->() -> xxx;
Current.Type = TT_TrailingReturnArrow;
} else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) {
Current.Type = determineStarAmpUsage(Current,
@@ -1467,7 +1494,8 @@ private:
// colon after this, this is the only place which annotates the identifier
// as a selector.)
Current.Type = TT_SelectorName;
- } else if (Current.isOneOf(tok::identifier, tok::kw_const) &&
+ } else if (Current.isOneOf(tok::identifier, tok::kw_const,
+ tok::kw_noexcept) &&
Current.Previous &&
!Current.Previous->isOneOf(tok::equal, tok::at) &&
Line.MightBeFunctionDecl && Contexts.size() == 1) {
@@ -1576,6 +1604,14 @@ private:
if (Tok.Next->is(tok::question))
return false;
+ // Functions which end with decorations like volatile, noexcept are unlikely
+ // to be casts.
+ if (Tok.Next->isOneOf(tok::kw_noexcept, tok::kw_volatile, tok::kw_const,
+ tok::kw_throw, tok::arrow, Keywords.kw_override,
+ Keywords.kw_final) ||
+ isCpp11AttributeSpecifier(*Tok.Next))
+ return false;
+
// As Java has no function types, a "(" after the ")" likely means that this
// is a cast.
if (Style.Language == FormatStyle::LK_Java && Tok.Next->is(tok::l_paren))
@@ -1647,7 +1683,8 @@ private:
const FormatToken *NextToken = Tok.getNextNonComment();
if (!NextToken ||
- NextToken->isOneOf(tok::arrow, tok::equal, tok::kw_const) ||
+ NextToken->isOneOf(tok::arrow, tok::equal, tok::kw_const,
+ tok::kw_noexcept) ||
(NextToken->is(tok::l_brace) && !NextToken->getNextNonComment()))
return TT_PointerOrReference;
@@ -1720,7 +1757,7 @@ private:
// Use heuristics to recognize unary operators.
if (PrevToken->isOneOf(tok::equal, tok::l_paren, tok::comma, tok::l_square,
tok::question, tok::colon, tok::kw_return,
- tok::kw_case, tok::at, tok::l_brace))
+ tok::kw_case, tok::at, tok::l_brace, tok::kw_throw))
return TT_UnaryOperator;
// There can't be two consecutive binary operators.
@@ -2160,7 +2197,8 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
if (Current->is(TT_LineComment)) {
if (Current->Previous->BlockKind == BK_BracedInit &&
Current->Previous->opensScope())
- Current->SpacesRequiredBefore = Style.Cpp11BracedListStyle ? 0 : 1;
+ Current->SpacesRequiredBefore =
+ (Style.Cpp11BracedListStyle && !Style.SpacesInParentheses) ? 0 : 1;
else
Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments;
@@ -2409,8 +2447,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign)
return 100;
if (Left.is(tok::l_paren) && Left.Previous &&
- (Left.Previous->isOneOf(tok::kw_if, tok::kw_for) ||
- Left.Previous->endsSequence(tok::kw_constexpr, tok::kw_if)))
+ (Left.Previous->is(tok::kw_for) || Left.Previous->isIf()))
return 1000;
if (Left.is(tok::equal) && InFunctionDecl)
return 110;
@@ -2429,6 +2466,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Left.is(TT_JavaAnnotation))
return 50;
+ if (Left.is(TT_UnaryOperator))
+ return 60;
if (Left.isOneOf(tok::plus, tok::comma) && Left.Previous &&
Left.Previous->isLabelString() &&
(Left.NextOperator || Left.OperatorIndex != 0))
@@ -2483,7 +2522,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
return Left.is(tok::hash);
if (Left.isOneOf(tok::hashhash, tok::hash))
return Right.is(tok::hash);
- if (Left.is(tok::l_paren) && Right.is(tok::r_paren))
+ if ((Left.is(tok::l_paren) && Right.is(tok::r_paren)) ||
+ (Left.is(tok::l_brace) && Left.BlockKind != BK_Block &&
+ Right.is(tok::r_brace) && Right.BlockKind != BK_Block))
return Style.SpaceInEmptyParentheses;
if (Left.is(tok::l_paren) || Right.is(tok::r_paren))
return (Right.is(TT_CastRParen) ||
@@ -2560,7 +2601,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
(Style.PointerAlignment != FormatStyle::PAS_Right &&
!Line.IsMultiVariableDeclStmt) &&
Left.Previous &&
- !Left.Previous->isOneOf(tok::l_paren, tok::coloncolon));
+ !Left.Previous->isOneOf(tok::l_paren, tok::coloncolon,
+ tok::l_square));
if (Right.is(tok::star) && Left.is(tok::l_paren))
return false;
const auto SpaceRequiredForArrayInitializerLSquare =
@@ -2575,8 +2617,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if (Left.is(tok::l_square))
return (Left.is(TT_ArrayInitializerLSquare) && Right.isNot(tok::r_square) &&
SpaceRequiredForArrayInitializerLSquare(Left, Style)) ||
- (Left.isOneOf(TT_ArraySubscriptLSquare,
- TT_StructuredBindingLSquare) &&
+ (Left.isOneOf(TT_ArraySubscriptLSquare, TT_StructuredBindingLSquare,
+ TT_LambdaLSquare) &&
Style.SpacesInSquareBrackets && Right.isNot(tok::r_square));
if (Right.is(tok::r_square))
return Right.MatchingParen &&
@@ -2585,7 +2627,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
Style)) ||
(Style.SpacesInSquareBrackets &&
Right.MatchingParen->isOneOf(TT_ArraySubscriptLSquare,
- TT_StructuredBindingLSquare)) ||
+ TT_StructuredBindingLSquare,
+ TT_LambdaLSquare)) ||
Right.MatchingParen->is(TT_AttributeParen));
if (Right.is(tok::l_square) &&
!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare,
@@ -2598,7 +2641,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
if ((Left.is(tok::l_brace) && Left.BlockKind != BK_Block) ||
(Right.is(tok::r_brace) && Right.MatchingParen &&
Right.MatchingParen->BlockKind != BK_Block))
- return !Style.Cpp11BracedListStyle;
+ return Style.Cpp11BracedListStyle ? Style.SpacesInParentheses : true;
if (Left.is(TT_BlockComment))
// No whitespace in x(/*foo=*/1), except for JavaScript.
return Style.Language == FormatStyle::LK_JavaScript ||
@@ -2609,10 +2652,10 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
return true;
return Line.Type == LT_ObjCDecl || Left.is(tok::semi) ||
(Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&
- (Left.isOneOf(tok::kw_if, tok::pp_elif, tok::kw_for, tok::kw_while,
+ (Left.isOneOf(tok::pp_elif, tok::kw_for, tok::kw_while,
tok::kw_switch, tok::kw_case, TT_ForEachMacro,
TT_ObjCForIn) ||
- Left.endsSequence(tok::kw_constexpr, tok::kw_if) ||
+ Left.isIf(Line.Type != LT_PreprocessorDirective) ||
(Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch,
tok::kw_new, tok::kw_delete) &&
(!Left.Previous || Left.Previous->isNot(tok::period))))) ||
@@ -2655,6 +2698,14 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
Right.MatchingParen->endsSequence(TT_DictLiteral, tok::at))
// Objective-C dictionary literal -> no space before closing brace.
return false;
+ if (Right.Type == TT_TrailingAnnotation &&
+ Right.isOneOf(tok::amp, tok::ampamp) &&
+ Left.isOneOf(tok::kw_const, tok::kw_volatile) &&
+ (!Right.Next || Right.Next->is(tok::semi)))
+ // Match const and volatile ref-qualifiers without any additional
+ // qualifiers such as
+ // void Fn() const &;
+ return Style.PointerAlignment != FormatStyle::PAS_Left;
return true;
}
@@ -2694,7 +2745,15 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
// and "%d %d"
if (Left.is(tok::numeric_constant) && Right.is(tok::percent))
return Right.WhitespaceRange.getEnd() != Right.WhitespaceRange.getBegin();
- } else if (Style.Language == FormatStyle::LK_JavaScript || Style.isCSharp()) {
+ } else if (Style.isCSharp()) {
+ // space between type and variable e.g. Dictionary<string,string> foo;
+ if (Left.is(TT_TemplateCloser) && Right.is(TT_StartOfName))
+ return true;
+ // space between keywords and paren e.g. "using ("
+ if (Right.is(tok::l_paren))
+ if (Left.is(tok::kw_using))
+ return spaceRequiredBeforeParens(Left);
+ } else if (Style.Language == FormatStyle::LK_JavaScript) {
if (Left.is(TT_JsFatArrow))
return true;
// for await ( ...
@@ -2739,6 +2798,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
tok::kw_void))
return true;
}
+ // `foo as const;` casts into a const type.
+ if (Left.endsSequence(tok::kw_const, Keywords.kw_as)) {
+ return false;
+ }
if ((Left.isOneOf(Keywords.kw_let, Keywords.kw_var, Keywords.kw_in,
tok::kw_const) ||
// "of" is only a keyword if it appears after another identifier
@@ -2842,9 +2905,19 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return false;
return true;
}
- if (Left.is(TT_UnaryOperator))
+ if (Left.is(TT_UnaryOperator)) {
+ // The alternative operators for ~ and ! are "compl" and "not".
+ // If they are used instead, we do not want to combine them with
+ // the token to the right, unless that is a left paren.
+ if (!Right.is(tok::l_paren)) {
+ if (Left.is(tok::exclaim) && Left.TokenText == "not")
+ return true;
+ if (Left.is(tok::tilde) && Left.TokenText == "compl")
+ return true;
+ }
return (Style.SpaceAfterLogicalNot && Left.is(tok::exclaim)) ||
Right.is(TT_BinaryOperator);
+ }
// If the next token is a binary operator or a selector name, we have
// incorrectly classified the parenthesis as a cast. FIXME: Detect correctly.
@@ -2857,13 +2930,13 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
(Style.Language == FormatStyle::LK_Proto && Left.is(TT_DictLiteral)))
return !Style.Cpp11BracedListStyle;
return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) &&
- (Style.Standard != FormatStyle::LS_Cpp11 || Style.SpacesInAngles);
+ (Style.Standard < FormatStyle::LS_Cpp11 || Style.SpacesInAngles);
}
if (Right.isOneOf(tok::arrow, tok::arrowstar, tok::periodstar) ||
Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) ||
(Right.is(tok::period) && Right.isNot(TT_DesignatedInitializerPeriod)))
return false;
- if (!Style.SpaceBeforeAssignmentOperators &&
+ if (!Style.SpaceBeforeAssignmentOperators && Left.isNot(TT_TemplateCloser) &&
Right.getPrecedence() == prec::Assignment)
return false;
if (Style.Language == FormatStyle::LK_Java && Right.is(tok::coloncolon) &&
@@ -2876,7 +2949,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd();
if (Right.is(tok::coloncolon) && !Left.isOneOf(tok::l_brace, tok::comment))
return (Left.is(TT_TemplateOpener) &&
- Style.Standard == FormatStyle::LS_Cpp03) ||
+ Style.Standard < FormatStyle::LS_Cpp11) ||
!(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square,
tok::kw___super, TT_TemplateCloser,
TT_TemplateOpener)) ||
@@ -3039,7 +3112,8 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
Style.BraceWrapping.AfterEnum) ||
(Line.startsWith(tok::kw_class) && Style.BraceWrapping.AfterClass) ||
(Line.startsWith(tok::kw_struct) && Style.BraceWrapping.AfterStruct);
- if (Left.is(TT_ObjCBlockLBrace) && !Style.AllowShortBlocksOnASingleLine)
+ if (Left.is(TT_ObjCBlockLBrace) &&
+ Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never)
return true;
if (Left.is(TT_LambdaLBrace)) {
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
index 702ac6c0d76e..537710029b00 100644
--- a/lib/Format/TokenAnnotator.h
+++ b/lib/Format/TokenAnnotator.h
@@ -114,8 +114,7 @@ public:
/// \c true if this line starts a namespace definition.
bool startsWithNamespace() const {
- return startsWith(tok::kw_namespace) ||
- startsWith(TT_NamespaceMacro) ||
+ return startsWith(tok::kw_namespace) || startsWith(TT_NamespaceMacro) ||
startsWith(tok::kw_inline, tok::kw_namespace) ||
startsWith(tok::kw_export, tok::kw_namespace);
}
diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp
index 3f3c80bc1ccf..8b8d357d9cbe 100644
--- a/lib/Format/UnwrappedLineFormatter.cpp
+++ b/lib/Format/UnwrappedLineFormatter.cpp
@@ -300,14 +300,30 @@ private:
// Try to merge a control statement block with left brace unwrapped
if (TheLine->Last->is(tok::l_brace) && TheLine->First != TheLine->Last &&
TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) {
- return Style.AllowShortBlocksOnASingleLine
+ return Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never
? tryMergeSimpleBlock(I, E, Limit)
: 0;
}
// Try to merge a control statement block with left brace wrapped
if (I[1]->First->is(tok::l_brace) &&
- TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) {
- return Style.BraceWrapping.AfterControlStatement
+ (TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for,
+ tok::kw_switch, tok::kw_try, tok::kw_do) ||
+ (TheLine->First->is(tok::r_brace) && TheLine->First->Next &&
+ TheLine->First->Next->isOneOf(tok::kw_else, tok::kw_catch))) &&
+ Style.BraceWrapping.AfterControlStatement ==
+ FormatStyle::BWACS_MultiLine) {
+ // If possible, merge the next line's wrapped left brace with the current
+ // line. Otherwise, leave it on the next line, as this is a multi-line
+ // control statement.
+ return (Style.ColumnLimit == 0 ||
+ TheLine->Last->TotalLength <= Style.ColumnLimit)
+ ? 1
+ : 0;
+ } else if (I[1]->First->is(tok::l_brace) &&
+ TheLine->First->isOneOf(tok::kw_if, tok::kw_while,
+ tok::kw_for)) {
+ return (Style.BraceWrapping.AfterControlStatement ==
+ FormatStyle::BWACS_Always)
? tryMergeSimpleBlock(I, E, Limit)
: 0;
}
@@ -317,7 +333,7 @@ private:
I != AnnotatedLines.begin() &&
I[-1]->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) {
unsigned MergedLines = 0;
- if (Style.AllowShortBlocksOnASingleLine) {
+ if (Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never) {
MergedLines = tryMergeSimpleBlock(I - 1, E, Limit);
// If we managed to merge the block, discard the first merged line
// since we are merging starting from I.
@@ -410,8 +426,10 @@ private:
SmallVectorImpl<AnnotatedLine *>::const_iterator E, unsigned Limit) {
if (Limit == 0)
return 0;
- if (Style.BraceWrapping.AfterControlStatement &&
- (I[1]->First->is(tok::l_brace) && !Style.AllowShortBlocksOnASingleLine))
+ if (Style.BraceWrapping.AfterControlStatement ==
+ FormatStyle::BWACS_Always &&
+ I[1]->First->is(tok::l_brace) &&
+ Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never)
return 0;
if (I[1]->InPPDirective != (*I)->InPPDirective ||
(I[1]->InPPDirective && I[1]->First->HasUnescapedNewline))
@@ -511,7 +529,7 @@ private:
if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::kw_try,
tok::kw___try, tok::kw_catch, tok::kw___finally,
tok::kw_for, tok::r_brace, Keywords.kw___except)) {
- if (!Style.AllowShortBlocksOnASingleLine)
+ if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never)
return 0;
// Don't merge when we can't except the case when
// the control statement block is empty
@@ -522,8 +540,9 @@ private:
return 0;
if (!Style.AllowShortIfStatementsOnASingleLine &&
Line.startsWith(tok::kw_if) &&
- Style.BraceWrapping.AfterControlStatement && I + 2 != E &&
- !I[2]->First->is(tok::r_brace))
+ Style.BraceWrapping.AfterControlStatement ==
+ FormatStyle::BWACS_Always &&
+ I + 2 != E && !I[2]->First->is(tok::r_brace))
return 0;
if (!Style.AllowShortLoopsOnASingleLine &&
Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) &&
@@ -532,8 +551,9 @@ private:
return 0;
if (!Style.AllowShortLoopsOnASingleLine &&
Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) &&
- Style.BraceWrapping.AfterControlStatement && I + 2 != E &&
- !I[2]->First->is(tok::r_brace))
+ Style.BraceWrapping.AfterControlStatement ==
+ FormatStyle::BWACS_Always &&
+ I + 2 != E && !I[2]->First->is(tok::r_brace))
return 0;
// FIXME: Consider an option to allow short exception handling clauses on
// a single line.
@@ -551,7 +571,7 @@ private:
(Tok->getNextNonComment() == nullptr ||
Tok->getNextNonComment()->is(tok::semi))) {
// We merge empty blocks even if the line exceeds the column limit.
- Tok->SpacesRequiredBefore = 0;
+ Tok->SpacesRequiredBefore = Style.SpaceInEmptyBlock ? 1 : 0;
Tok->CanBreakBefore = true;
return 1;
} else if (Limit != 0 && !Line.startsWithNamespace() &&
@@ -596,6 +616,17 @@ private:
if (Tok->Next && Tok->Next->is(tok::kw_else))
return 0;
+ // Don't merge a trailing multi-line control statement block like:
+ // } else if (foo &&
+ // bar)
+ // { <-- current Line
+ // baz();
+ // }
+ if (Line.First == Line.Last &&
+ Style.BraceWrapping.AfterControlStatement ==
+ FormatStyle::BWACS_MultiLine)
+ return 0;
+
return 2;
}
} else if (I[1]->First->is(tok::l_brace)) {
@@ -607,7 +638,7 @@ private:
return 0;
Limit -= 2;
unsigned MergedLines = 0;
- if (Style.AllowShortBlocksOnASingleLine ||
+ if (Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never ||
(I[1]->First == I[1]->Last && I + 2 != E &&
I[2]->First->is(tok::r_brace))) {
MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
@@ -1192,6 +1223,12 @@ void UnwrappedLineFormatter::formatFirstToken(
if (Newlines)
Indent = NewlineIndent;
+ // If in Whitemsmiths mode, indent start and end of blocks
+ if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths) {
+ if (RootToken.isOneOf(tok::l_brace, tok::r_brace, tok::kw_case))
+ Indent += Style.IndentWidth;
+ }
+
// Preprocessor directives get indented before the hash only if specified
if (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash &&
(Line.Type == LT_PreprocessorDirective ||
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index a35e98ae5503..bbe05602f6da 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -145,7 +145,7 @@ public:
else if (!Parser.Line->Tokens.empty())
Parser.CurrentLines = &Parser.Line->Tokens.back().Children;
PreBlockLine = std::move(Parser.Line);
- Parser.Line = llvm::make_unique<UnwrappedLine>();
+ Parser.Line = std::make_unique<UnwrappedLine>();
Parser.Line->Level = PreBlockLine->Level;
Parser.Line->InPPDirective = PreBlockLine->InPPDirective;
}
@@ -174,8 +174,7 @@ public:
const FormatStyle &Style, unsigned &LineLevel)
: CompoundStatementIndenter(Parser, LineLevel,
Style.BraceWrapping.AfterControlStatement,
- Style.BraceWrapping.IndentBraces) {
- }
+ Style.BraceWrapping.IndentBraces) {}
CompoundStatementIndenter(UnwrappedLineParser *Parser, unsigned &LineLevel,
bool WrapBrace, bool IndentBrace)
: LineLevel(LineLevel), OldLineLevel(LineLevel) {
@@ -1168,7 +1167,8 @@ void UnwrappedLineParser::parseStructuralElement() {
case tok::objc_autoreleasepool:
nextToken();
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BraceWrapping.AfterControlStatement)
+ if (Style.BraceWrapping.AfterControlStatement ==
+ FormatStyle::BWACS_Always)
addUnwrappedLine();
parseBlock(/*MustBeDeclaration=*/false);
}
@@ -1180,7 +1180,8 @@ void UnwrappedLineParser::parseStructuralElement() {
// Skip synchronization object
parseParens();
if (FormatTok->Tok.is(tok::l_brace)) {
- if (Style.BraceWrapping.AfterControlStatement)
+ if (Style.BraceWrapping.AfterControlStatement ==
+ FormatStyle::BWACS_Always)
addUnwrappedLine();
parseBlock(/*MustBeDeclaration=*/false);
}
@@ -1215,7 +1216,9 @@ void UnwrappedLineParser::parseStructuralElement() {
case tok::kw_typedef:
nextToken();
if (FormatTok->isOneOf(Keywords.kw_NS_ENUM, Keywords.kw_NS_OPTIONS,
- Keywords.kw_CF_ENUM, Keywords.kw_CF_OPTIONS))
+ Keywords.kw_CF_ENUM, Keywords.kw_CF_OPTIONS,
+ Keywords.kw_CF_CLOSED_ENUM,
+ Keywords.kw_NS_CLOSED_ENUM))
parseEnum();
break;
case tok::kw_struct:
@@ -1350,7 +1353,7 @@ void UnwrappedLineParser::parseStructuralElement() {
(TokenCount == 2 && Line->Tokens.front().Tok->is(tok::comment))) {
if (FormatTok->Tok.is(tok::colon) && !Line->MustBeDeclaration) {
Line->Tokens.begin()->Tok->MustBreakBefore = true;
- parseLabel();
+ parseLabel(!Style.IndentGotoLabels);
return;
}
// Recognize function-like macro usages without trailing semicolon as
@@ -1439,8 +1442,11 @@ bool UnwrappedLineParser::tryToParseLambda() {
case tok::identifier:
case tok::numeric_constant:
case tok::coloncolon:
+ case tok::kw_class:
case tok::kw_mutable:
case tok::kw_noexcept:
+ case tok::kw_template:
+ case tok::kw_typename:
nextToken();
break;
// Specialization of a template with an integer parameter can contain
@@ -1454,6 +1460,9 @@ bool UnwrappedLineParser::tryToParseLambda() {
// followed by an `a->b` expression, such as:
// ([obj func:arg] + a->b)
// Otherwise the code below would parse as a lambda.
+ //
+ // FIXME: This heuristic is incorrect for C++20 generic lambdas with
+ // explicit template lists: []<bool b = true && false>(U &&u){}
case tok::plus:
case tok::minus:
case tok::exclaim:
@@ -1755,7 +1764,7 @@ void UnwrappedLineParser::parseSquare(bool LambdaIntroducer) {
void UnwrappedLineParser::parseIfThenElse() {
assert(FormatTok->Tok.is(tok::kw_if) && "'if' expected");
nextToken();
- if (FormatTok->Tok.is(tok::kw_constexpr))
+ if (FormatTok->Tok.isOneOf(tok::kw_constexpr, tok::identifier))
nextToken();
if (FormatTok->Tok.is(tok::l_paren))
parseParens();
@@ -1872,8 +1881,13 @@ void UnwrappedLineParser::parseNamespace() {
if (InitialToken.is(TT_NamespaceMacro)) {
parseParens();
} else {
- while (FormatTok->isOneOf(tok::identifier, tok::coloncolon))
- nextToken();
+ while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw_inline,
+ tok::l_square)) {
+ if (FormatTok->is(tok::l_square))
+ parseSquare();
+ else
+ nextToken();
+ }
}
if (FormatTok->Tok.is(tok::l_brace)) {
if (ShouldBreakBeforeBrace(Style, InitialToken))
@@ -1964,18 +1978,21 @@ void UnwrappedLineParser::parseDoWhile() {
parseStructuralElement();
}
-void UnwrappedLineParser::parseLabel() {
+void UnwrappedLineParser::parseLabel(bool LeftAlignLabel) {
nextToken();
unsigned OldLineLevel = Line->Level;
if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0))
--Line->Level;
+ if (LeftAlignLabel)
+ Line->Level = 0;
if (CommentsBeforeNextToken.empty() && FormatTok->Tok.is(tok::l_brace)) {
CompoundStatementIndenter Indenter(this, Line->Level,
Style.BraceWrapping.AfterCaseLabel,
Style.BraceWrapping.IndentBraces);
parseBlock(/*MustBeDeclaration=*/false);
if (FormatTok->Tok.is(tok::kw_break)) {
- if (Style.BraceWrapping.AfterControlStatement)
+ if (Style.BraceWrapping.AfterControlStatement ==
+ FormatStyle::BWACS_Always)
addUnwrappedLine();
parseStructuralElement();
}
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index e1b35317c7c0..5d9bafc429a7 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -106,7 +106,7 @@ private:
void parseTryCatch();
void parseForOrWhileLoop();
void parseDoWhile();
- void parseLabel();
+ void parseLabel(bool LeftAlignLabel = false);
void parseCaseLabel();
void parseSwitch();
void parseNamespace();
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index 23fbf94c7588..5a44500d355f 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -17,8 +17,8 @@
namespace clang {
namespace format {
-bool WhitespaceManager::Change::IsBeforeInFile::
-operator()(const Change &C1, const Change &C2) const {
+bool WhitespaceManager::Change::IsBeforeInFile::operator()(
+ const Change &C1, const Change &C2) const {
return SourceMgr.isBeforeInTranslationUnit(
C1.OriginalWhitespaceRange.getBegin(),
C2.OriginalWhitespaceRange.getBegin());
@@ -815,19 +815,24 @@ void WhitespaceManager::appendIndentText(std::string &Text,
Text.append(Spaces, ' ');
break;
case FormatStyle::UT_Always: {
- unsigned FirstTabWidth =
- Style.TabWidth - WhitespaceStartColumn % Style.TabWidth;
- // Insert only spaces when we want to end up before the next tab.
- if (Spaces < FirstTabWidth || Spaces == 1) {
+ if (Style.TabWidth) {
+ unsigned FirstTabWidth =
+ Style.TabWidth - WhitespaceStartColumn % Style.TabWidth;
+
+ // Insert only spaces when we want to end up before the next tab.
+ if (Spaces < FirstTabWidth || Spaces == 1) {
+ Text.append(Spaces, ' ');
+ break;
+ }
+ // Align to the next tab.
+ Spaces -= FirstTabWidth;
+ Text.append("\t");
+
+ Text.append(Spaces / Style.TabWidth, '\t');
+ Text.append(Spaces % Style.TabWidth, ' ');
+ } else if (Spaces == 1) {
Text.append(Spaces, ' ');
- break;
}
- // Align to the next tab.
- Spaces -= FirstTabWidth;
- Text.append("\t");
-
- Text.append(Spaces / Style.TabWidth, '\t');
- Text.append(Spaces % Style.TabWidth, ' ');
break;
}
case FormatStyle::UT_ForIndentation:
@@ -837,14 +842,16 @@ void WhitespaceManager::appendIndentText(std::string &Text,
// the first one.
if (Indentation > Spaces)
Indentation = Spaces;
- unsigned Tabs = Indentation / Style.TabWidth;
- Text.append(Tabs, '\t');
- Spaces -= Tabs * Style.TabWidth;
+ if (Style.TabWidth) {
+ unsigned Tabs = Indentation / Style.TabWidth;
+ Text.append(Tabs, '\t');
+ Spaces -= Tabs * Style.TabWidth;
+ }
}
Text.append(Spaces, ' ');
break;
case FormatStyle::UT_ForContinuationAndIndentation:
- if (WhitespaceStartColumn == 0) {
+ if (WhitespaceStartColumn == 0 && Style.TabWidth) {
unsigned Tabs = Spaces / Style.TabWidth;
Text.append(Tabs, '\t');
Spaces -= Tabs * Style.TabWidth;
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 26154ee2e856..043b2541b8f8 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -139,7 +139,7 @@ namespace {
std::unique_ptr<ASTConsumer>
clang::CreateASTPrinter(std::unique_ptr<raw_ostream> Out,
StringRef FilterString) {
- return llvm::make_unique<ASTPrinter>(std::move(Out), ASTPrinter::Print,
+ return std::make_unique<ASTPrinter>(std::move(Out), ASTPrinter::Print,
ADOF_Default, FilterString);
}
@@ -148,7 +148,7 @@ clang::CreateASTDumper(std::unique_ptr<raw_ostream> Out, StringRef FilterString,
bool DumpDecls, bool Deserialize, bool DumpLookups,
ASTDumpOutputFormat Format) {
assert((DumpDecls || Deserialize || DumpLookups) && "nothing to dump");
- return llvm::make_unique<ASTPrinter>(std::move(Out),
+ return std::make_unique<ASTPrinter>(std::move(Out),
Deserialize ? ASTPrinter::DumpFull :
DumpDecls ? ASTPrinter::Dump :
ASTPrinter::None, Format,
@@ -156,7 +156,7 @@ clang::CreateASTDumper(std::unique_ptr<raw_ostream> Out, StringRef FilterString,
}
std::unique_ptr<ASTConsumer> clang::CreateASTDeclNodeLister() {
- return llvm::make_unique<ASTDeclNodeLister>(nullptr);
+ return std::make_unique<ASTDeclNodeLister>(nullptr);
}
//===----------------------------------------------------------------------===//
@@ -193,5 +193,5 @@ void ASTViewer::HandleTopLevelSingleDecl(Decl *D) {
}
std::unique_ptr<ASTConsumer> clang::CreateASTViewer() {
- return llvm::make_unique<ASTViewer>();
+ return std::make_unique<ASTViewer>();
}
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 7445a94cfe59..f5e291b7fe17 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -30,6 +30,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/LangStandard.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
@@ -83,8 +84,8 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Mutex.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
@@ -95,6 +96,7 @@
#include <cstdio>
#include <cstdlib>
#include <memory>
+#include <mutex>
#include <string>
#include <tuple>
#include <utility>
@@ -435,7 +437,6 @@ void ASTUnit::CacheCodeCompletionResults() {
| (1LL << CodeCompletionContext::CCC_UnionTag)
| (1LL << CodeCompletionContext::CCC_ClassOrStructTag)
| (1LL << CodeCompletionContext::CCC_Type)
- | (1LL << CodeCompletionContext::CCC_Symbol)
| (1LL << CodeCompletionContext::CCC_SymbolOrNewName)
| (1LL << CodeCompletionContext::CCC_ParenthesizedExpression);
@@ -819,7 +820,7 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile(
/*isysroot=*/"",
/*DisableValidation=*/disableValid, AllowPCHWithCompilerErrors);
- AST->Reader->setListener(llvm::make_unique<ASTInfoCollector>(
+ AST->Reader->setListener(std::make_unique<ASTInfoCollector>(
*AST->PP, AST->Ctx.get(), *AST->HSOpts, *AST->PPOpts, *AST->LangOpts,
AST->TargetOpts, AST->Target, Counter));
@@ -999,9 +1000,9 @@ public:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override {
CI.getPreprocessor().addPPCallbacks(
- llvm::make_unique<MacroDefinitionTrackerPPCallbacks>(
+ std::make_unique<MacroDefinitionTrackerPPCallbacks>(
Unit.getCurrentTopLevelHashValue()));
- return llvm::make_unique<TopLevelDeclTrackerConsumer>(
+ return std::make_unique<TopLevelDeclTrackerConsumer>(
Unit, Unit.getCurrentTopLevelHashValue());
}
@@ -1049,7 +1050,7 @@ public:
}
std::unique_ptr<PPCallbacks> createPPCallbacks() override {
- return llvm::make_unique<MacroDefinitionTrackerPPCallbacks>(Hash);
+ return std::make_unique<MacroDefinitionTrackerPPCallbacks>(Hash);
}
private:
@@ -1154,7 +1155,7 @@ bool ASTUnit::Parse(std::shared_ptr<PCHContainerOperations> PCHContainerOps,
InputKind::Source &&
"FIXME: AST inputs not yet supported here!");
assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
- InputKind::LLVM_IR &&
+ Language::LLVM_IR &&
"IR inputs not support here!");
// Configure the various subsystems.
@@ -1587,7 +1588,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
InputKind::Source &&
"FIXME: AST inputs not yet supported here!");
assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
- InputKind::LLVM_IR &&
+ Language::LLVM_IR &&
"IR inputs not support here!");
// Configure the various subsystems.
@@ -1624,15 +1625,15 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
if (Persistent && !TrackerAct) {
Clang->getPreprocessor().addPPCallbacks(
- llvm::make_unique<MacroDefinitionTrackerPPCallbacks>(
+ std::make_unique<MacroDefinitionTrackerPPCallbacks>(
AST->getCurrentTopLevelHashValue()));
std::vector<std::unique_ptr<ASTConsumer>> Consumers;
if (Clang->hasASTConsumer())
Consumers.push_back(Clang->takeASTConsumer());
- Consumers.push_back(llvm::make_unique<TopLevelDeclTrackerConsumer>(
+ Consumers.push_back(std::make_unique<TopLevelDeclTrackerConsumer>(
*AST, AST->getCurrentTopLevelHashValue()));
Clang->setASTConsumer(
- llvm::make_unique<MultiplexConsumer>(std::move(Consumers)));
+ std::make_unique<MultiplexConsumer>(std::move(Consumers)));
}
if (llvm::Error Err = Act->Execute()) {
consumeError(std::move(Err)); // FIXME this drops errors on the floor.
@@ -1735,6 +1736,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion,
bool AllowPCHWithCompilerErrors, SkipFunctionBodiesScope SkipFunctionBodies,
bool SingleFileParse, bool UserFilesAreVolatile, bool ForSerialization,
+ bool RetainExcludedConditionalBlocks,
llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
assert(Diags.get() && "no DiagnosticsEngine was provided");
@@ -1762,6 +1764,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName;
PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors;
PPOpts.SingleFileParseMode = SingleFileParse;
+ PPOpts.RetainExcludedConditionalBlocks = RetainExcludedConditionalBlocks;
// Override the resources path.
CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
@@ -2211,7 +2214,7 @@ void ASTUnit::CodeComplete(
InputKind::Source &&
"FIXME: AST inputs not yet supported here!");
assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() !=
- InputKind::LLVM_IR &&
+ Language::LLVM_IR &&
"IR inputs not support here!");
// Use the source and file managers that we were given.
@@ -2299,26 +2302,19 @@ bool ASTUnit::Save(StringRef File) {
SmallString<128> TempPath;
TempPath = File;
TempPath += "-%%%%%%%%";
- int fd;
- if (llvm::sys::fs::createUniqueFile(TempPath, fd, TempPath))
- return true;
-
// FIXME: Can we somehow regenerate the stat cache here, or do we need to
// unconditionally create a stat cache when we parse the file?
- llvm::raw_fd_ostream Out(fd, /*shouldClose=*/true);
-
- serialize(Out);
- Out.close();
- if (Out.has_error()) {
- Out.clear_error();
- return true;
- }
- if (llvm::sys::fs::rename(TempPath, File)) {
- llvm::sys::fs::remove(TempPath);
+ if (llvm::Error Err = llvm::writeFileAtomically(
+ TempPath, File, [this](llvm::raw_ostream &Out) {
+ return serialize(Out) ? llvm::make_error<llvm::StringError>(
+ "ASTUnit serialization failed",
+ llvm::inconvertibleErrorCode())
+ : llvm::Error::success();
+ })) {
+ consumeError(std::move(Err));
return true;
}
-
return false;
}
@@ -2369,13 +2365,13 @@ void ASTUnit::TranslateStoredDiagnostics(
// Rebuild the StoredDiagnostic.
if (SD.Filename.empty())
continue;
- const FileEntry *FE = FileMgr.getFile(SD.Filename);
+ auto FE = FileMgr.getFile(SD.Filename);
if (!FE)
continue;
SourceLocation FileLoc;
auto ItFileID = PreambleSrcLocCache.find(SD.Filename);
if (ItFileID == PreambleSrcLocCache.end()) {
- FileID FID = SrcMgr.translateFile(FE);
+ FileID FID = SrcMgr.translateFile(*FE);
FileLoc = SrcMgr.getLocForStartOfFile(FID);
PreambleSrcLocCache[SD.Filename] = FileLoc;
} else {
@@ -2668,17 +2664,17 @@ bool ASTUnit::isModuleFile() const {
InputKind ASTUnit::getInputKind() const {
auto &LangOpts = getLangOpts();
- InputKind::Language Lang;
+ Language Lang;
if (LangOpts.OpenCL)
- Lang = InputKind::OpenCL;
+ Lang = Language::OpenCL;
else if (LangOpts.CUDA)
- Lang = InputKind::CUDA;
+ Lang = Language::CUDA;
else if (LangOpts.RenderScript)
- Lang = InputKind::RenderScript;
+ Lang = Language::RenderScript;
else if (LangOpts.CPlusPlus)
- Lang = LangOpts.ObjC ? InputKind::ObjCXX : InputKind::CXX;
+ Lang = LangOpts.ObjC ? Language::ObjCXX : Language::CXX;
else
- Lang = LangOpts.ObjC ? InputKind::ObjC : InputKind::C;
+ Lang = LangOpts.ObjC ? Language::ObjC : Language::C;
InputKind::Format Fmt = InputKind::Source;
if (LangOpts.getCompilingModule() == LangOptions::CMK_ModuleMap)
@@ -2692,20 +2688,20 @@ InputKind ASTUnit::getInputKind() const {
#ifndef NDEBUG
ASTUnit::ConcurrencyState::ConcurrencyState() {
- Mutex = new llvm::sys::MutexImpl(/*recursive=*/true);
+ Mutex = new std::recursive_mutex;
}
ASTUnit::ConcurrencyState::~ConcurrencyState() {
- delete static_cast<llvm::sys::MutexImpl *>(Mutex);
+ delete static_cast<std::recursive_mutex *>(Mutex);
}
void ASTUnit::ConcurrencyState::start() {
- bool acquired = static_cast<llvm::sys::MutexImpl *>(Mutex)->tryacquire();
+ bool acquired = static_cast<std::recursive_mutex *>(Mutex)->try_lock();
assert(acquired && "Concurrent access to ASTUnit!");
}
void ASTUnit::ConcurrencyState::finish() {
- static_cast<llvm::sys::MutexImpl *>(Mutex)->release();
+ static_cast<std::recursive_mutex *>(Mutex)->unlock();
}
#else // NDEBUG
diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp
index 48154ecf4742..29fee7246d14 100644
--- a/lib/Frontend/ChainedIncludesSource.cpp
+++ b/lib/Frontend/ChainedIncludesSource.cpp
@@ -158,7 +158,7 @@ IntrusiveRefCntPtr<ExternalSemaSource> clang::createChainedIncludesSource(
auto Buffer = std::make_shared<PCHBuffer>();
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions;
- auto consumer = llvm::make_unique<PCHGenerator>(
+ auto consumer = std::make_unique<PCHGenerator>(
Clang->getPreprocessor(), Clang->getModuleCache(), "-", /*isysroot=*/"",
Buffer, Extensions, /*AllowASTWithErrors=*/true);
Clang->getASTContext().setASTMutationListener(
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index cf0267549e75..c409c07ff133 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -13,6 +13,7 @@
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangStandard.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Stack.h"
#include "clang/Basic/TargetInfo.h"
@@ -49,8 +50,6 @@
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
-#include <sys/stat.h>
-#include <system_error>
#include <time.h>
#include <utility>
@@ -85,6 +84,16 @@ void CompilerInstance::setDiagnostics(DiagnosticsEngine *Value) {
Diagnostics = Value;
}
+void CompilerInstance::setVerboseOutputStream(raw_ostream &Value) {
+ OwnedVerboseOutputStream.release();
+ VerboseOutputStream = &Value;
+}
+
+void CompilerInstance::setVerboseOutputStream(std::unique_ptr<raw_ostream> Value) {
+ OwnedVerboseOutputStream.swap(Value);
+ VerboseOutputStream = OwnedVerboseOutputStream.get();
+}
+
void CompilerInstance::setTarget(TargetInfo *Value) { Target = Value; }
void CompilerInstance::setAuxTarget(TargetInfo *Value) { AuxTarget = Value; }
@@ -161,7 +170,7 @@ static void collectIncludePCH(CompilerInstance &CI,
StringRef PCHInclude = PPOpts.ImplicitPCHInclude;
FileManager &FileMgr = CI.getFileManager();
- const DirectoryEntry *PCHDir = FileMgr.getDirectory(PCHInclude);
+ auto PCHDir = FileMgr.getDirectory(PCHInclude);
if (!PCHDir) {
MDC->addFile(PCHInclude);
return;
@@ -169,7 +178,7 @@ static void collectIncludePCH(CompilerInstance &CI,
std::error_code EC;
SmallString<128> DirNative;
- llvm::sys::path::native(PCHDir->getName(), DirNative);
+ llvm::sys::path::native((*PCHDir)->getName(), DirNative);
llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem();
SimpleASTReaderListener Validator(CI.getPreprocessor());
for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC), DirEnd;
@@ -214,9 +223,9 @@ static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
raw_ostream *OS = &llvm::errs();
if (DiagOpts->DiagnosticLogFile != "-") {
// Create the output stream.
- auto FileOS = llvm::make_unique<llvm::raw_fd_ostream>(
+ auto FileOS = std::make_unique<llvm::raw_fd_ostream>(
DiagOpts->DiagnosticLogFile, EC,
- llvm::sys::fs::F_Append | llvm::sys::fs::F_Text);
+ llvm::sys::fs::OF_Append | llvm::sys::fs::OF_Text);
if (EC) {
Diags.Report(diag::warn_fe_cc_log_diagnostics_failure)
<< DiagOpts->DiagnosticLogFile << EC.message();
@@ -228,7 +237,7 @@ static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
}
// Chain in the diagnostic client which will log the diagnostics.
- auto Logger = llvm::make_unique<LogDiagnosticPrinter>(*OS, DiagOpts,
+ auto Logger = std::make_unique<LogDiagnosticPrinter>(*OS, DiagOpts,
std::move(StreamOwner));
if (CodeGenOpts)
Logger->setDwarfDebugFlags(CodeGenOpts->DwarfDebugFlags);
@@ -342,7 +351,7 @@ static void InitializeFileRemapping(DiagnosticsEngine &Diags,
// Remap files in the source manager (with other files).
for (const auto &RF : InitOpts.RemappedFiles) {
// Find the file that we're mapping to.
- const FileEntry *ToFile = FileMgr.getFile(RF.second);
+ auto ToFile = FileMgr.getFile(RF.second);
if (!ToFile) {
Diags.Report(diag::err_fe_remap_missing_to_file) << RF.first << RF.second;
continue;
@@ -350,7 +359,7 @@ static void InitializeFileRemapping(DiagnosticsEngine &Diags,
// Create the file entry for the file that we're mapping from.
const FileEntry *FromFile =
- FileMgr.getVirtualFile(RF.first, ToFile->getSize(), 0);
+ FileMgr.getVirtualFile(RF.first, (*ToFile)->getSize(), 0);
if (!FromFile) {
Diags.Report(diag::err_fe_remap_missing_from_file) << RF.first;
continue;
@@ -358,7 +367,7 @@ static void InitializeFileRemapping(DiagnosticsEngine &Diags,
// Override the contents of the "from" file with the contents of
// the "to" file.
- SourceMgr.overrideFileContents(FromFile, ToFile);
+ SourceMgr.overrideFileContents(FromFile, *ToFile);
}
SourceMgr.setOverridenFilesKeepOriginalName(
@@ -509,7 +518,8 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource(
PP, ModuleCache, &Context, PCHContainerRdr, Extensions,
Sysroot.empty() ? "" : Sysroot.data(), DisablePCHValidation,
AllowPCHWithCompilerErrors, /*AllowConfigurationMismatch*/ false,
- HSOpts.ModulesValidateSystemHeaders, UseGlobalModuleIndex));
+ HSOpts.ModulesValidateSystemHeaders, HSOpts.ValidateASTInputFilesContent,
+ UseGlobalModuleIndex));
// We need the external source to be set up before we read the AST, because
// eagerly-deserialized declarations may use it.
@@ -558,7 +568,7 @@ static bool EnableCodeCompletion(Preprocessor &PP,
unsigned Column) {
// Tell the source manager to chop off the given file at a specific
// line and column.
- const FileEntry *Entry = PP.getFileManager().getFile(Filename);
+ auto Entry = PP.getFileManager().getFile(Filename);
if (!Entry) {
PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file)
<< Filename;
@@ -566,7 +576,7 @@ static bool EnableCodeCompletion(Preprocessor &PP,
}
// Truncate the named file at the given line/column.
- PP.SetCodeCompletionPoint(Entry, Line, Column);
+ PP.SetCodeCompletionPoint(*Entry, Line, Column);
return false;
}
@@ -666,7 +676,7 @@ CompilerInstance::createDefaultOutputFile(bool Binary, StringRef InFile,
}
std::unique_ptr<raw_pwrite_stream> CompilerInstance::createNullOutputFile() {
- return llvm::make_unique<llvm::raw_null_ostream>();
+ return std::make_unique<llvm::raw_null_ostream>();
}
std::unique_ptr<raw_pwrite_stream>
@@ -775,7 +785,7 @@ std::unique_ptr<llvm::raw_pwrite_stream> CompilerInstance::createOutputFile(
OSFile = OutFile;
OS.reset(new llvm::raw_fd_ostream(
OSFile, Error,
- (Binary ? llvm::sys::fs::F_None : llvm::sys::fs::F_Text)));
+ (Binary ? llvm::sys::fs::OF_None : llvm::sys::fs::OF_Text)));
if (Error)
return nullptr;
}
@@ -792,7 +802,7 @@ std::unique_ptr<llvm::raw_pwrite_stream> CompilerInstance::createOutputFile(
if (!Binary || OS->supportsSeeking())
return std::move(OS);
- auto B = llvm::make_unique<llvm::buffer_ostream>(*OS);
+ auto B = std::make_unique<llvm::buffer_ostream>(*OS);
assert(!NonSeekStream);
NonSeekStream = std::move(OS);
return std::move(B);
@@ -830,32 +840,39 @@ bool CompilerInstance::InitializeSourceManager(
// Figure out where to get and map in the main file.
if (InputFile != "-") {
- const FileEntry *File = FileMgr.getFile(InputFile, /*OpenFile=*/true);
- if (!File) {
+ auto FileOrErr = FileMgr.getFileRef(InputFile, /*OpenFile=*/true);
+ if (!FileOrErr) {
+ // FIXME: include the error in the diagnostic.
+ consumeError(FileOrErr.takeError());
Diags.Report(diag::err_fe_error_reading) << InputFile;
return false;
}
+ FileEntryRef File = *FileOrErr;
// The natural SourceManager infrastructure can't currently handle named
// pipes, but we would at least like to accept them for the main
// file. Detect them here, read them with the volatile flag so FileMgr will
// pick up the correct size, and simply override their contents as we do for
// STDIN.
- if (File->isNamedPipe()) {
- auto MB = FileMgr.getBufferForFile(File, /*isVolatile=*/true);
+ if (File.getFileEntry().isNamedPipe()) {
+ auto MB =
+ FileMgr.getBufferForFile(&File.getFileEntry(), /*isVolatile=*/true);
if (MB) {
// Create a new virtual file that will have the correct size.
- File = FileMgr.getVirtualFile(InputFile, (*MB)->getBufferSize(), 0);
- SourceMgr.overrideFileContents(File, std::move(*MB));
+ const FileEntry *FE =
+ FileMgr.getVirtualFile(InputFile, (*MB)->getBufferSize(), 0);
+ SourceMgr.overrideFileContents(FE, std::move(*MB));
+ SourceMgr.setMainFileID(
+ SourceMgr.createFileID(FE, SourceLocation(), Kind));
} else {
Diags.Report(diag::err_cannot_open_file) << InputFile
<< MB.getError().message();
return false;
}
+ } else {
+ SourceMgr.setMainFileID(
+ SourceMgr.createFileID(File, SourceLocation(), Kind));
}
-
- SourceMgr.setMainFileID(
- SourceMgr.createFileID(File, SourceLocation(), Kind));
} else {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> SBOrErr =
llvm::MemoryBuffer::getSTDIN();
@@ -884,9 +901,12 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!");
assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!");
- // FIXME: Take this as an argument, once all the APIs we used have moved to
- // taking it as an input instead of hard-coding llvm::errs.
- raw_ostream &OS = llvm::errs();
+ // Mark this point as the bottom of the stack if we don't have somewhere
+ // better. We generally expect frontend actions to be invoked with (nearly)
+ // DesiredStackSpace available.
+ noteBottomOfStack();
+
+ raw_ostream &OS = getVerboseOutputStream();
if (!Act.PrepareToExecute(*this))
return false;
@@ -986,8 +1006,8 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
StringRef StatsFile = getFrontendOpts().StatsFile;
if (!StatsFile.empty()) {
std::error_code EC;
- auto StatS = llvm::make_unique<llvm::raw_fd_ostream>(StatsFile, EC,
- llvm::sys::fs::F_Text);
+ auto StatS = std::make_unique<llvm::raw_fd_ostream>(
+ StatsFile, EC, llvm::sys::fs::OF_Text);
if (EC) {
getDiagnostics().Report(diag::warn_fe_unable_to_open_stats_file)
<< StatsFile << EC.message();
@@ -1001,14 +1021,14 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
/// Determine the appropriate source input kind based on language
/// options.
-static InputKind::Language getLanguageFromOptions(const LangOptions &LangOpts) {
+static Language getLanguageFromOptions(const LangOptions &LangOpts) {
if (LangOpts.OpenCL)
- return InputKind::OpenCL;
+ return Language::OpenCL;
if (LangOpts.CUDA)
- return InputKind::CUDA;
+ return Language::CUDA;
if (LangOpts.ObjC)
- return LangOpts.CPlusPlus ? InputKind::ObjCXX : InputKind::ObjC;
- return LangOpts.CPlusPlus ? InputKind::CXX : InputKind::C;
+ return LangOpts.CPlusPlus ? Language::ObjCXX : Language::ObjC;
+ return LangOpts.CPlusPlus ? Language::CXX : Language::C;
}
/// Compile a module file for the given module, using the options
@@ -1154,7 +1174,9 @@ static const FileEntry *getPublicModuleMap(const FileEntry *File,
llvm::sys::path::append(PublicFilename, "module.modulemap");
else
return nullptr;
- return FileMgr.getFile(PublicFilename);
+ if (auto FE = FileMgr.getFile(PublicFilename))
+ return *FE;
+ return nullptr;
}
/// Compile a module file for the given module, using the options
@@ -1367,22 +1389,22 @@ static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro,
/// Write a new timestamp file with the given path.
static void writeTimestampFile(StringRef TimestampFile) {
std::error_code EC;
- llvm::raw_fd_ostream Out(TimestampFile.str(), EC, llvm::sys::fs::F_None);
+ llvm::raw_fd_ostream Out(TimestampFile.str(), EC, llvm::sys::fs::OF_None);
}
/// Prune the module cache of modules that haven't been accessed in
/// a long time.
static void pruneModuleCache(const HeaderSearchOptions &HSOpts) {
- struct stat StatBuf;
+ llvm::sys::fs::file_status StatBuf;
llvm::SmallString<128> TimestampFile;
TimestampFile = HSOpts.ModuleCachePath;
assert(!TimestampFile.empty());
llvm::sys::path::append(TimestampFile, "modules.timestamp");
// Try to stat() the timestamp file.
- if (::stat(TimestampFile.c_str(), &StatBuf)) {
+ if (std::error_code EC = llvm::sys::fs::status(TimestampFile, StatBuf)) {
// If the timestamp file wasn't there, create one now.
- if (errno == ENOENT) {
+ if (EC == std::errc::no_such_file_or_directory) {
writeTimestampFile(TimestampFile);
}
return;
@@ -1390,7 +1412,8 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) {
// Check whether the time stamp is older than our pruning interval.
// If not, do nothing.
- time_t TimeStampModTime = StatBuf.st_mtime;
+ time_t TimeStampModTime =
+ llvm::sys::toTimeT(StatBuf.getLastModificationTime());
time_t CurrentTime = time(nullptr);
if (CurrentTime - TimeStampModTime <= time_t(HSOpts.ModuleCachePruneInterval))
return;
@@ -1422,11 +1445,11 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) {
// Look at this file. If we can't stat it, there's nothing interesting
// there.
- if (::stat(File->path().c_str(), &StatBuf))
+ if (llvm::sys::fs::status(File->path(), StatBuf))
continue;
// If the file has been used recently enough, leave it there.
- time_t FileAccessTime = StatBuf.st_atime;
+ time_t FileAccessTime = llvm::sys::toTimeT(StatBuf.getLastAccessedTime());
if (CurrentTime - FileAccessTime <=
time_t(HSOpts.ModuleCachePruneAfter)) {
continue;
@@ -1467,7 +1490,7 @@ void CompilerInstance::createModuleManager() {
const PreprocessorOptions &PPOpts = getPreprocessorOpts();
std::unique_ptr<llvm::Timer> ReadTimer;
if (FrontendTimerGroup)
- ReadTimer = llvm::make_unique<llvm::Timer>("reading_modules",
+ ReadTimer = std::make_unique<llvm::Timer>("reading_modules",
"Reading modules",
*FrontendTimerGroup);
ModuleManager = new ASTReader(
@@ -1477,6 +1500,7 @@ void CompilerInstance::createModuleManager() {
/*AllowASTWithCompilerErrors=*/false,
/*AllowConfigurationMismatch=*/false,
HSOpts.ModulesValidateSystemHeaders,
+ HSOpts.ValidateASTInputFilesContent,
getFrontendOpts().UseGlobalModuleIndex, std::move(ReadTimer));
if (hasASTConsumer()) {
ModuleManager->setDeserializationListener(
@@ -1562,7 +1586,7 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) {
SourceLocation())
<= DiagnosticsEngine::Warning;
- auto Listener = llvm::make_unique<ReadModuleNames>(*this);
+ auto Listener = std::make_unique<ReadModuleNames>(*this);
auto &ListenerRef = *Listener;
ASTReader::ListenerScope ReadModuleNamesListener(*ModuleManager,
std::move(Listener));
@@ -1718,8 +1742,9 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
if (Source != ModuleCache && !Module) {
Module = PP->getHeaderSearchInfo().lookupModule(ModuleName, true,
!IsInclusionDirective);
+ auto ModuleFile = FileMgr->getFile(ModuleFileName);
if (!Module || !Module->getASTFile() ||
- FileMgr->getFile(ModuleFileName) != Module->getASTFile()) {
+ !ModuleFile || (*ModuleFile != Module->getASTFile())) {
// Error out if Module does not refer to the file in the prebuilt
// module path.
getDiagnostics().Report(ModuleNameLoc, diag::err_module_prebuilt)
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 8a9844096f08..665695ec3b18 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -18,6 +18,7 @@
#include "clang/Basic/FileSystemOptions.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/LangStandard.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Sanitizers.h"
#include "clang/Basic/SourceLocation.h"
@@ -34,7 +35,6 @@
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
-#include "clang/Frontend/LangStandard.h"
#include "clang/Frontend/MigratorOptions.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
#include "clang/Frontend/Utils.h"
@@ -122,7 +122,7 @@ CompilerInvocationBase::~CompilerInvocationBase() = default;
static unsigned getOptimizationLevel(ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags) {
unsigned DefaultOpt = llvm::CodeGenOpt::None;
- if (IK.getLanguage() == InputKind::OpenCL && !Args.hasArg(OPT_cl_opt_disable))
+ if (IK.getLanguage() == Language::OpenCL && !Args.hasArg(OPT_cl_opt_disable))
DefaultOpt = llvm::CodeGenOpt::Default;
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
@@ -303,7 +303,7 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
.Case("true", true)
.Case("false", false)
.Default(false);
- Opts.DisableAllChecks = Args.hasArg(OPT_analyzer_disable_all_checks);
+ Opts.DisableAllCheckers = Args.hasArg(OPT_analyzer_disable_all_checks);
Opts.visualizeExplodedGraphWithGraphViz =
Args.hasArg(OPT_analyzer_viz_egraph_graphviz);
@@ -324,18 +324,18 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
getLastArgIntValue(Args, OPT_analyzer_inline_max_stack_depth,
Opts.InlineMaxStackDepth, Diags);
- Opts.CheckersControlList.clear();
+ Opts.CheckersAndPackages.clear();
for (const Arg *A :
Args.filtered(OPT_analyzer_checker, OPT_analyzer_disable_checker)) {
A->claim();
- bool enable = (A->getOption().getID() == OPT_analyzer_checker);
+ bool IsEnabled = A->getOption().getID() == OPT_analyzer_checker;
// We can have a list of comma separated checker names, e.g:
// '-analyzer-checker=cocoa,unix'
- StringRef checkerList = A->getValue();
- SmallVector<StringRef, 4> checkers;
- checkerList.split(checkers, ",");
- for (auto checker : checkers)
- Opts.CheckersControlList.emplace_back(checker, enable);
+ StringRef CheckerAndPackageList = A->getValue();
+ SmallVector<StringRef, 16> CheckersAndPackages;
+ CheckerAndPackageList.split(CheckersAndPackages, ",");
+ for (const StringRef CheckerOrPackage : CheckersAndPackages)
+ Opts.CheckersAndPackages.emplace_back(CheckerOrPackage, IsEnabled);
}
// Go through the analyzer configuration options.
@@ -464,6 +464,35 @@ static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts,
// At this point, AnalyzerOptions is configured. Let's validate some options.
+ // FIXME: Here we try to validate the silenced checkers or packages are valid.
+ // The current approach only validates the registered checkers which does not
+ // contain the runtime enabled checkers and optimally we would validate both.
+ if (!AnOpts.RawSilencedCheckersAndPackages.empty()) {
+ std::vector<StringRef> Checkers =
+ AnOpts.getRegisteredCheckers(/*IncludeExperimental=*/true);
+ std::vector<StringRef> Packages =
+ AnOpts.getRegisteredPackages(/*IncludeExperimental=*/true);
+
+ SmallVector<StringRef, 16> CheckersAndPackages;
+ AnOpts.RawSilencedCheckersAndPackages.split(CheckersAndPackages, ";");
+
+ for (const StringRef CheckerOrPackage : CheckersAndPackages) {
+ if (Diags) {
+ bool IsChecker = CheckerOrPackage.contains('.');
+ bool IsValidName =
+ IsChecker
+ ? llvm::find(Checkers, CheckerOrPackage) != Checkers.end()
+ : llvm::find(Packages, CheckerOrPackage) != Packages.end();
+
+ if (!IsValidName)
+ Diags->Report(diag::err_unknown_analyzer_checker_or_package)
+ << CheckerOrPackage;
+ }
+
+ AnOpts.SilencedCheckersAndPackages.emplace_back(CheckerOrPackage);
+ }
+ }
+
if (!Diags)
return;
@@ -729,6 +758,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.CodeViewGHash = Args.hasArg(OPT_gcodeview_ghash);
Opts.MacroDebugInfo = Args.hasArg(OPT_debug_info_macro);
Opts.WholeProgramVTables = Args.hasArg(OPT_fwhole_program_vtables);
+ Opts.VirtualFunctionElimination =
+ Args.hasArg(OPT_fvirtual_function_elimination);
Opts.LTOVisibilityPublicStd = Args.hasArg(OPT_flto_visibility_public_std);
Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
Opts.SplitDwarfOutput = Args.getLastArgValue(OPT_split_dwarf_output);
@@ -748,10 +779,14 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DisableLLVMPasses = Args.hasArg(OPT_disable_llvm_passes);
Opts.DisableLifetimeMarkers = Args.hasArg(OPT_disable_lifetimemarkers);
+ const llvm::Triple::ArchType DebugEntryValueArchs[] = {
+ llvm::Triple::x86, llvm::Triple::x86_64, llvm::Triple::aarch64,
+ llvm::Triple::arm, llvm::Triple::armeb};
+
llvm::Triple T(TargetOpts.Triple);
- llvm::Triple::ArchType Arch = T.getArch();
if (Opts.OptimizationLevel > 0 &&
- (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64))
+ Opts.getDebugInfo() >= codegenoptions::LimitedDebugInfo &&
+ llvm::is_contained(DebugEntryValueArchs, T.getArch()))
Opts.EnableDebugEntryValues = Args.hasArg(OPT_femit_debug_entry_values);
Opts.DisableO0ImplyOptNone = Args.hasArg(OPT_disable_O0_optnone);
@@ -823,8 +858,32 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases);
Opts.CodeModel = TargetOpts.CodeModel;
Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass);
- Opts.DisableFPElim =
- (Args.hasArg(OPT_mdisable_fp_elim) || Args.hasArg(OPT_pg));
+
+ // Handle -mframe-pointer option.
+ if (Arg *A = Args.getLastArg(OPT_mframe_pointer_EQ)) {
+ CodeGenOptions::FramePointerKind FP;
+ StringRef Name = A->getValue();
+ bool ValidFP = true;
+ if (Name == "none")
+ FP = CodeGenOptions::FramePointerKind::None;
+ else if (Name == "non-leaf")
+ FP = CodeGenOptions::FramePointerKind::NonLeaf;
+ else if (Name == "all")
+ FP = CodeGenOptions::FramePointerKind::All;
+ else {
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
+ Success = false;
+ ValidFP = false;
+ }
+ if (ValidFP)
+ Opts.setFramePointer(FP);
+ }
+
+ // -pg may override -mframe-pointer
+ // TODO: This should be merged into getFramePointerKind in Clang.cpp.
+ if (Args.hasArg(OPT_pg))
+ Opts.setFramePointer(CodeGenOptions::FramePointerKind::All);
+
Opts.DisableFree = Args.hasArg(OPT_disable_free);
Opts.DiscardValueNames = Args.hasArg(OPT_discard_value_names);
Opts.DisableTailCalls = Args.hasArg(OPT_mdisable_tail_calls);
@@ -864,6 +923,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.NumRegisterParameters = getLastArgIntValue(Args, OPT_mregparm, 0, Diags);
Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
+ Opts.NoWarn = Args.hasArg(OPT_massembler_no_warn);
Opts.EnableSegmentedStacks = Args.hasArg(OPT_split_stacks);
Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
Opts.IncrementalLinkerCompatible =
@@ -871,7 +931,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.PIECopyRelocations =
Args.hasArg(OPT_mpie_copy_relocations);
Opts.NoPLT = Args.hasArg(OPT_fno_plt);
- Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer);
Opts.SaveTempLabels = Args.hasArg(OPT_msave_temp_labels);
Opts.NoDwarfDirectoryAsm = Args.hasArg(OPT_fno_dwarf_directory_asm);
Opts.SoftFloat = Args.hasArg(OPT_msoft_float);
@@ -921,7 +980,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.LTOUnit = Args.hasFlag(OPT_flto_unit, OPT_fno_lto_unit, false);
Opts.EnableSplitLTOUnit = Args.hasArg(OPT_fsplit_lto_unit);
if (Arg *A = Args.getLastArg(OPT_fthinlto_index_EQ)) {
- if (IK.getLanguage() != InputKind::LLVM_IR)
+ if (IK.getLanguage() != Language::LLVM_IR)
Diags.Report(diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-x ir";
Opts.ThinLTOIndexFile = Args.getLastArgValue(OPT_fthinlto_index_EQ);
@@ -1115,6 +1174,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.SanitizeCfiCrossDso = Args.hasArg(OPT_fsanitize_cfi_cross_dso);
Opts.SanitizeCfiICallGeneralizePointers =
Args.hasArg(OPT_fsanitize_cfi_icall_generalize_pointers);
+ Opts.SanitizeCfiCanonicalJumpTables =
+ Args.hasArg(OPT_fsanitize_cfi_canonical_jump_tables);
Opts.SanitizeStats = Args.hasArg(OPT_fsanitize_stats);
if (Arg *A = Args.getLastArg(
OPT_fsanitize_address_poison_custom_array_cookie,
@@ -1262,7 +1323,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
if (Opts.DiagnosticsWithHotness && !UsingProfile &&
// An IR file will contain PGO as metadata
- IK.getLanguage() != InputKind::LLVM_IR)
+ IK.getLanguage() != Language::LLVM_IR)
Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo)
<< "-fdiagnostics-show-hotness";
@@ -1675,23 +1736,30 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ProgramAction = frontend::GenerateHeaderModule; break;
case OPT_emit_pch:
Opts.ProgramAction = frontend::GeneratePCH; break;
- case OPT_emit_iterface_stubs: {
- llvm::Optional<frontend::ActionKind> ProgramAction =
- llvm::StringSwitch<llvm::Optional<frontend::ActionKind>>(
- Args.hasArg(OPT_iterface_stub_version_EQ)
- ? Args.getLastArgValue(OPT_iterface_stub_version_EQ)
- : "")
- .Case("experimental-yaml-elf-v1",
- frontend::GenerateInterfaceYAMLExpV1)
- .Case("experimental-tapi-elf-v1",
- frontend::GenerateInterfaceTBEExpV1)
- .Default(llvm::None);
- if (!ProgramAction)
+ case OPT_emit_interface_stubs: {
+ StringRef ArgStr =
+ Args.hasArg(OPT_interface_stub_version_EQ)
+ ? Args.getLastArgValue(OPT_interface_stub_version_EQ)
+ : "experimental-ifs-v1";
+ if (ArgStr == "experimental-yaml-elf-v1" ||
+ ArgStr == "experimental-tapi-elf-v1") {
+ std::string ErrorMessage =
+ "Invalid interface stub format: " + ArgStr.str() +
+ " is deprecated.";
+ Diags.Report(diag::err_drv_invalid_value)
+ << "Must specify a valid interface stub format type, ie: "
+ "-interface-stub-version=experimental-ifs-v1"
+ << ErrorMessage;
+ } else if (ArgStr != "experimental-ifs-v1") {
+ std::string ErrorMessage =
+ "Invalid interface stub format: " + ArgStr.str() + ".";
Diags.Report(diag::err_drv_invalid_value)
- << "Must specify a valid interface stub format type using "
- << "-interface-stub-version=<experimental-tapi-elf-v1 | "
- "experimental-yaml-elf-v1>";
- Opts.ProgramAction = *ProgramAction;
+ << "Must specify a valid interface stub format type, ie: "
+ "-interface-stub-version=experimental-ifs-v1"
+ << ErrorMessage;
+ } else {
+ Opts.ProgramAction = frontend::GenerateInterfaceIfsExpV1;
+ }
break;
}
case OPT_init_only:
@@ -1773,6 +1841,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ShowTimers = Args.hasArg(OPT_ftime_report);
Opts.PrintSupportedCPUs = Args.hasArg(OPT_print_supported_cpus);
Opts.TimeTrace = Args.hasArg(OPT_ftime_trace);
+ Opts.TimeTraceGranularity = getLastArgIntValue(
+ Args, OPT_ftime_trace_granularity_EQ, Opts.TimeTraceGranularity, Diags);
Opts.ShowVersion = Args.hasArg(OPT_version);
Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge);
Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
@@ -1877,7 +1947,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
<< "ARC migration" << "ObjC migration";
}
- InputKind DashX(InputKind::Unknown);
+ InputKind DashX(Language::Unknown);
if (const Arg *A = Args.getLastArg(OPT_x)) {
StringRef XValue = A->getValue();
@@ -1890,33 +1960,33 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
// Principal languages.
DashX = llvm::StringSwitch<InputKind>(XValue)
- .Case("c", InputKind::C)
- .Case("cl", InputKind::OpenCL)
- .Case("cuda", InputKind::CUDA)
- .Case("hip", InputKind::HIP)
- .Case("c++", InputKind::CXX)
- .Case("objective-c", InputKind::ObjC)
- .Case("objective-c++", InputKind::ObjCXX)
- .Case("renderscript", InputKind::RenderScript)
- .Default(InputKind::Unknown);
+ .Case("c", Language::C)
+ .Case("cl", Language::OpenCL)
+ .Case("cuda", Language::CUDA)
+ .Case("hip", Language::HIP)
+ .Case("c++", Language::CXX)
+ .Case("objective-c", Language::ObjC)
+ .Case("objective-c++", Language::ObjCXX)
+ .Case("renderscript", Language::RenderScript)
+ .Default(Language::Unknown);
// "objc[++]-cpp-output" is an acceptable synonym for
// "objective-c[++]-cpp-output".
if (DashX.isUnknown() && Preprocessed && !IsHeaderFile && !ModuleMap)
DashX = llvm::StringSwitch<InputKind>(XValue)
- .Case("objc", InputKind::ObjC)
- .Case("objc++", InputKind::ObjCXX)
- .Default(InputKind::Unknown);
+ .Case("objc", Language::ObjC)
+ .Case("objc++", Language::ObjCXX)
+ .Default(Language::Unknown);
// Some special cases cannot be combined with suffixes.
if (DashX.isUnknown() && !Preprocessed && !ModuleMap && !IsHeaderFile)
DashX = llvm::StringSwitch<InputKind>(XValue)
- .Case("cpp-output", InputKind(InputKind::C).getPreprocessed())
- .Case("assembler-with-cpp", InputKind::Asm)
+ .Case("cpp-output", InputKind(Language::C).getPreprocessed())
+ .Case("assembler-with-cpp", Language::Asm)
.Cases("ast", "pcm",
- InputKind(InputKind::Unknown, InputKind::Precompiled))
- .Case("ir", InputKind::LLVM_IR)
- .Default(InputKind::Unknown);
+ InputKind(Language::Unknown, InputKind::Precompiled))
+ .Case("ir", Language::LLVM_IR)
+ .Default(Language::Unknown);
if (DashX.isUnknown())
Diags.Report(diag::err_drv_invalid_value)
@@ -1940,7 +2010,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
StringRef(Inputs[i]).rsplit('.').second);
// FIXME: Warn on this?
if (IK.isUnknown())
- IK = InputKind::C;
+ IK = Language::C;
// FIXME: Remove this hack.
if (i == 0)
DashX = IK;
@@ -1997,6 +2067,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
Opts.AddPrebuiltModulePath(A->getValue());
Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash);
Opts.ModulesHashContent = Args.hasArg(OPT_fmodules_hash_content);
+ Opts.ModulesStrictContextHash = Args.hasArg(OPT_fmodules_strict_context_hash);
Opts.ModulesValidateDiagnosticOptions =
!Args.hasArg(OPT_fmodules_disable_diagnostic_validation);
Opts.ImplicitModuleMaps = Args.hasArg(OPT_fimplicit_module_maps);
@@ -2011,6 +2082,8 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args,
getLastArgUInt64Value(Args, OPT_fbuild_session_timestamp, 0);
Opts.ModulesValidateSystemHeaders =
Args.hasArg(OPT_fmodules_validate_system_headers);
+ Opts.ValidateASTInputFilesContent =
+ Args.hasArg(OPT_fvalidate_ast_input_files_content);
if (const Arg *A = Args.getLastArg(OPT_fmodule_format_EQ))
Opts.ModuleFormat = A->getValue();
@@ -2114,7 +2187,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
// FIXME: Perhaps a better model would be for a single source file to have
// multiple language standards (C / C++ std, ObjC std, OpenCL std, OpenMP std)
// simultaneously active?
- if (IK.getLanguage() == InputKind::Asm) {
+ if (IK.getLanguage() == Language::Asm) {
Opts.AsmPreprocessor = 1;
} else if (IK.isObjectiveC()) {
Opts.ObjC = 1;
@@ -2123,17 +2196,17 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
if (LangStd == LangStandard::lang_unspecified) {
// Based on the base language, pick one.
switch (IK.getLanguage()) {
- case InputKind::Unknown:
- case InputKind::LLVM_IR:
+ case Language::Unknown:
+ case Language::LLVM_IR:
llvm_unreachable("Invalid input kind!");
- case InputKind::OpenCL:
+ case Language::OpenCL:
LangStd = LangStandard::lang_opencl10;
break;
- case InputKind::CUDA:
+ case Language::CUDA:
LangStd = LangStandard::lang_cuda;
break;
- case InputKind::Asm:
- case InputKind::C:
+ case Language::Asm:
+ case Language::C:
#if defined(CLANG_DEFAULT_STD_C)
LangStd = CLANG_DEFAULT_STD_C;
#else
@@ -2144,25 +2217,25 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
LangStd = LangStandard::lang_gnu11;
#endif
break;
- case InputKind::ObjC:
+ case Language::ObjC:
#if defined(CLANG_DEFAULT_STD_C)
LangStd = CLANG_DEFAULT_STD_C;
#else
LangStd = LangStandard::lang_gnu11;
#endif
break;
- case InputKind::CXX:
- case InputKind::ObjCXX:
+ case Language::CXX:
+ case Language::ObjCXX:
#if defined(CLANG_DEFAULT_STD_CXX)
LangStd = CLANG_DEFAULT_STD_CXX;
#else
LangStd = LangStandard::lang_gnucxx14;
#endif
break;
- case InputKind::RenderScript:
+ case Language::RenderScript:
LangStd = LangStandard::lang_c99;
break;
- case InputKind::HIP:
+ case Language::HIP:
LangStd = LangStandard::lang_hip;
break;
}
@@ -2182,6 +2255,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.Digraphs = Std.hasDigraphs();
Opts.GNUMode = Std.isGNUMode();
Opts.GNUInline = !Opts.C99 && !Opts.CPlusPlus;
+ Opts.GNUCVersion = 0;
Opts.HexFloats = Std.hasHexFloats();
Opts.ImplicitInt = Std.hasImplicitInt();
@@ -2202,7 +2276,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
if (Opts.OpenCL) {
Opts.AltiVec = 0;
Opts.ZVector = 0;
- Opts.LaxVectorConversions = 0;
+ Opts.setLaxVectorConversions(LangOptions::LaxVectorConversionKind::None);
Opts.setDefaultFPContractMode(LangOptions::FPC_On);
Opts.NativeHalfType = 1;
Opts.NativeHalfArgsAndReturns = 1;
@@ -2219,13 +2293,13 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
}
}
- Opts.HIP = IK.getLanguage() == InputKind::HIP;
- Opts.CUDA = IK.getLanguage() == InputKind::CUDA || Opts.HIP;
+ Opts.HIP = IK.getLanguage() == Language::HIP;
+ Opts.CUDA = IK.getLanguage() == Language::CUDA || Opts.HIP;
if (Opts.CUDA)
// Set default FP_CONTRACT to FAST.
Opts.setDefaultFPContractMode(LangOptions::FPC_Fast);
- Opts.RenderScript = IK.getLanguage() == InputKind::RenderScript;
+ Opts.RenderScript = IK.getLanguage() == Language::RenderScript;
if (Opts.RenderScript) {
Opts.NativeHalfType = 1;
Opts.NativeHalfArgsAndReturns = 1;
@@ -2273,32 +2347,31 @@ static Visibility parseVisibility(Arg *arg, ArgList &args,
static bool IsInputCompatibleWithStandard(InputKind IK,
const LangStandard &S) {
switch (IK.getLanguage()) {
- case InputKind::Unknown:
- case InputKind::LLVM_IR:
+ case Language::Unknown:
+ case Language::LLVM_IR:
llvm_unreachable("should not parse language flags for this input");
- case InputKind::C:
- case InputKind::ObjC:
- case InputKind::RenderScript:
- return S.getLanguage() == InputKind::C;
+ case Language::C:
+ case Language::ObjC:
+ case Language::RenderScript:
+ return S.getLanguage() == Language::C;
- case InputKind::OpenCL:
- return S.getLanguage() == InputKind::OpenCL;
+ case Language::OpenCL:
+ return S.getLanguage() == Language::OpenCL;
- case InputKind::CXX:
- case InputKind::ObjCXX:
- return S.getLanguage() == InputKind::CXX;
+ case Language::CXX:
+ case Language::ObjCXX:
+ return S.getLanguage() == Language::CXX;
- case InputKind::CUDA:
+ case Language::CUDA:
// FIXME: What -std= values should be permitted for CUDA compilations?
- return S.getLanguage() == InputKind::CUDA ||
- S.getLanguage() == InputKind::CXX;
+ return S.getLanguage() == Language::CUDA ||
+ S.getLanguage() == Language::CXX;
- case InputKind::HIP:
- return S.getLanguage() == InputKind::CXX ||
- S.getLanguage() == InputKind::HIP;
+ case Language::HIP:
+ return S.getLanguage() == Language::CXX || S.getLanguage() == Language::HIP;
- case InputKind::Asm:
+ case Language::Asm:
// Accept (and ignore) all -std= values.
// FIXME: The -std= value is not ignored; it affects the tokenization
// and preprocessing rules if we're preprocessing this asm input.
@@ -2311,29 +2384,29 @@ static bool IsInputCompatibleWithStandard(InputKind IK,
/// Get language name for given input kind.
static const StringRef GetInputKindName(InputKind IK) {
switch (IK.getLanguage()) {
- case InputKind::C:
+ case Language::C:
return "C";
- case InputKind::ObjC:
+ case Language::ObjC:
return "Objective-C";
- case InputKind::CXX:
+ case Language::CXX:
return "C++";
- case InputKind::ObjCXX:
+ case Language::ObjCXX:
return "Objective-C++";
- case InputKind::OpenCL:
+ case Language::OpenCL:
return "OpenCL";
- case InputKind::CUDA:
+ case Language::CUDA:
return "CUDA";
- case InputKind::RenderScript:
+ case Language::RenderScript:
return "RenderScript";
- case InputKind::HIP:
+ case Language::HIP:
return "HIP";
- case InputKind::Asm:
+ case Language::Asm:
return "Asm";
- case InputKind::LLVM_IR:
+ case Language::LLVM_IR:
return "LLVM IR";
- case InputKind::Unknown:
+ case Language::Unknown:
break;
}
llvm_unreachable("unknown input language");
@@ -2346,13 +2419,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
// FIXME: Cleanup per-file based stuff.
LangStandard::Kind LangStd = LangStandard::lang_unspecified;
if (const Arg *A = Args.getLastArg(OPT_std_EQ)) {
- LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue())
-#define LANGSTANDARD(id, name, lang, desc, features) \
- .Case(name, LangStandard::lang_##id)
-#define LANGSTANDARD_ALIAS(id, alias) \
- .Case(alias, LangStandard::lang_##id)
-#include "clang/Frontend/LangStandards.def"
- .Default(LangStandard::lang_unspecified);
+ LangStd = LangStandard::getLangKind(A->getValue());
if (LangStd == LangStandard::lang_unspecified) {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
@@ -2370,13 +2437,13 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
#define LANGSTANDARD_ALIAS(id, alias) \
if (KindValue == LangStandard::lang_##id) ++NumAliases;
#define LANGSTANDARD_ALIAS_DEPR(id, alias)
-#include "clang/Frontend/LangStandards.def"
+#include "clang/Basic/LangStandards.def"
Diag << NumAliases;
#define LANGSTANDARD(id, name, lang, desc, features)
#define LANGSTANDARD_ALIAS(id, alias) \
if (KindValue == LangStandard::lang_##id) Diag << alias;
#define LANGSTANDARD_ALIAS_DEPR(id, alias)
-#include "clang/Frontend/LangStandards.def"
+#include "clang/Basic/LangStandards.def"
}
}
} else {
@@ -2408,7 +2475,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
.Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11)
.Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12)
.Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20)
- .Case("c++", LangStandard::lang_openclcpp)
+ .Cases("clc++", "CLC++", LangStandard::lang_openclcpp)
.Default(LangStandard::lang_unspecified);
if (OpenCLLangStd == LangStandard::lang_unspecified) {
@@ -2461,6 +2528,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.CUDADeviceApproxTranscendentals = 1;
Opts.GPURelocatableDeviceCode = Args.hasArg(OPT_fgpu_rdc);
+ Opts.HIPUseNewLaunchAPI = Args.hasArg(OPT_fhip_new_launch_api);
if (Opts.ObjC) {
if (Arg *arg = Args.getLastArg(OPT_fobjc_runtime_EQ)) {
@@ -2512,6 +2580,21 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
(Opts.ObjCRuntime.getKind() == ObjCRuntime::FragileMacOSX);
}
+ if (Arg *A = Args.getLastArg(options::OPT_fgnuc_version_EQ)) {
+ // Check that the version has 1 to 3 components and the minor and patch
+ // versions fit in two decimal digits.
+ VersionTuple GNUCVer;
+ bool Invalid = GNUCVer.tryParse(A->getValue());
+ unsigned Major = GNUCVer.getMajor();
+ unsigned Minor = GNUCVer.getMinor().getValueOr(0);
+ unsigned Patch = GNUCVer.getSubminor().getValueOr(0);
+ if (Invalid || GNUCVer.getBuild() || Minor >= 100 || Patch >= 100) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue();
+ }
+ Opts.GNUCVersion = Major * 100 * 100 + Minor * 100 + Patch;
+ }
+
if (Args.hasArg(OPT_fgnu89_inline)) {
if (Opts.CPlusPlus)
Diags.Report(diag::err_drv_argument_not_allowed_with)
@@ -2611,8 +2694,18 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
Opts.ConstStrings = Args.hasFlag(OPT_fconst_strings, OPT_fno_const_strings,
Opts.ConstStrings);
- if (Args.hasArg(OPT_fno_lax_vector_conversions))
- Opts.LaxVectorConversions = 0;
+ if (Arg *A = Args.getLastArg(OPT_flax_vector_conversions_EQ)) {
+ using LaxKind = LangOptions::LaxVectorConversionKind;
+ if (auto Kind = llvm::StringSwitch<Optional<LaxKind>>(A->getValue())
+ .Case("none", LaxKind::None)
+ .Case("integer", LaxKind::Integer)
+ .Case("all", LaxKind::All)
+ .Default(llvm::None))
+ Opts.setLaxVectorConversions(*Kind);
+ else
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue();
+ }
if (Args.hasArg(OPT_fno_threadsafe_statics))
Opts.ThreadsafeStatics = 0;
Opts.Exceptions = Args.hasArg(OPT_fexceptions);
@@ -2630,9 +2723,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.FixedPoint;
// Handle exception personalities
- Arg *A = Args.getLastArg(options::OPT_fsjlj_exceptions,
- options::OPT_fseh_exceptions,
- options::OPT_fdwarf_exceptions);
+ Arg *A = Args.getLastArg(
+ options::OPT_fsjlj_exceptions, options::OPT_fseh_exceptions,
+ options::OPT_fdwarf_exceptions, options::OPT_fwasm_exceptions);
if (A) {
const Option &Opt = A->getOption();
llvm::Triple T(TargetOpts.Triple);
@@ -2643,6 +2736,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.SjLjExceptions = Opt.matches(options::OPT_fsjlj_exceptions);
Opts.SEHExceptions = Opt.matches(options::OPT_fseh_exceptions);
Opts.DWARFExceptions = Opt.matches(options::OPT_fdwarf_exceptions);
+ Opts.WasmExceptions = Opt.matches(options::OPT_fwasm_exceptions);
}
Opts.ExternCNoUnwind = Args.hasArg(OPT_fexternc_nounwind);
@@ -2727,6 +2821,10 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
getLastArgIntValue(Args, OPT_fconstexpr_depth, 512, Diags);
Opts.ConstexprStepLimit =
getLastArgIntValue(Args, OPT_fconstexpr_steps, 1048576, Diags);
+ Opts.EnableNewConstInterp =
+ Args.hasArg(OPT_fexperimental_new_constant_interpreter);
+ Opts.ForceNewConstInterp =
+ Args.hasArg(OPT_fforce_experimental_new_constant_interpreter);
Opts.BracketDepth = getLastArgIntValue(Args, OPT_fbracket_depth, 256, Diags);
Opts.DelayedTemplateParsing = Args.hasArg(OPT_fdelayed_template_parsing);
Opts.NumLargeByValueCopy =
@@ -2876,8 +2974,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
}
}
- // Check if -fopenmp is specified.
- Opts.OpenMP = Args.hasArg(options::OPT_fopenmp) ? 1 : 0;
+ // Check if -fopenmp is specified and set default version to 4.5.
+ Opts.OpenMP = Args.hasArg(options::OPT_fopenmp) ? 45 : 0;
// Check if -fopenmp-simd is specified.
bool IsSimdSpecified =
Args.hasFlag(options::OPT_fopenmp_simd, options::OPT_fno_openmp_simd,
@@ -3108,6 +3206,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.setClangABICompat(LangOptions::ClangABI::Ver6);
else if (Major <= 7)
Opts.setClangABICompat(LangOptions::ClangABI::Ver7);
+ else if (Major <= 9)
+ Opts.setClangABICompat(LangOptions::ClangABI::Ver9);
} else if (Ver != "latest") {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
@@ -3136,8 +3236,7 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
case frontend::GenerateModuleInterface:
case frontend::GenerateHeaderModule:
case frontend::GeneratePCH:
- case frontend::GenerateInterfaceYAMLExpV1:
- case frontend::GenerateInterfaceTBEExpV1:
+ case frontend::GenerateInterfaceIfsExpV1:
case frontend::ParseSyntaxOnly:
case frontend::ModuleFileInfo:
case frontend::VerifyPCH:
@@ -3253,6 +3352,8 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
// "editor placeholder in source file" error in PP only mode.
if (isStrictlyPreprocessorAction(Action))
Opts.LexEditorPlaceholders = false;
+
+ Opts.SetUpStaticAnalyzer = Args.hasArg(OPT_setup_static_analyzer);
}
static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
@@ -3315,18 +3416,16 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args,
}
bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
- const char *const *ArgBegin,
- const char *const *ArgEnd,
+ ArrayRef<const char *> CommandLineArgs,
DiagnosticsEngine &Diags) {
bool Success = true;
// Parse the arguments.
- std::unique_ptr<OptTable> Opts = createDriverOptTable();
+ const OptTable &Opts = getDriverOptTable();
const unsigned IncludedFlagsBitmask = options::CC1Option;
unsigned MissingArgIndex, MissingArgCount;
- InputArgList Args =
- Opts->ParseArgs(llvm::makeArrayRef(ArgBegin, ArgEnd), MissingArgIndex,
- MissingArgCount, IncludedFlagsBitmask);
+ InputArgList Args = Opts.ParseArgs(CommandLineArgs, MissingArgIndex,
+ MissingArgCount, IncludedFlagsBitmask);
LangOptions &LangOpts = *Res.getLangOpts();
// Check for missing argument error.
@@ -3340,7 +3439,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
for (const auto *A : Args.filtered(OPT_UNKNOWN)) {
auto ArgString = A->getAsString(Args);
std::string Nearest;
- if (Opts->findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
+ if (Opts.findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
Diags.Report(diag::err_drv_unknown_argument) << ArgString;
else
Diags.Report(diag::err_drv_unknown_argument_with_suggestion)
@@ -3351,6 +3450,11 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
Success &= ParseAnalyzerArgs(*Res.getAnalyzerOpts(), Args, Diags);
Success &= ParseMigratorArgs(Res.getMigratorOpts(), Args);
ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), Args);
+ if (!Res.getDependencyOutputOpts().OutputFile.empty() &&
+ Res.getDependencyOutputOpts().Targets.empty()) {
+ Diags.Report(diag::err_fe_dependency_file_requires_MT);
+ Success = false;
+ }
Success &=
ParseDiagnosticArgs(Res.getDiagnosticOpts(), Args, &Diags,
false /*DefaultDiagColor*/, false /*DefaultShowOpt*/);
@@ -3366,7 +3470,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
Res.getFileSystemOpts().WorkingDir);
llvm::Triple T(Res.getTargetOpts().Triple);
if (DashX.getFormat() == InputKind::Precompiled ||
- DashX.getLanguage() == InputKind::LLVM_IR) {
+ DashX.getLanguage() == Language::LLVM_IR) {
// ObjCAAutoRefCount and Sanitize LangOpts are used to setup the
// PassManager in BackendUtil.cpp. They need to be initializd no matter
// what the input type is.
@@ -3380,7 +3484,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
Diags, LangOpts.Sanitize);
} else {
// Other LangOpts are only initialized when the input is not AST or LLVM IR.
- // FIXME: Should we really be calling this for an InputKind::Asm input?
+ // FIXME: Should we really be calling this for an Language::Asm input?
ParseLangArgs(LangOpts, Args, DashX, Res.getTargetOpts(),
Res.getPreprocessorOpts(), Diags);
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
@@ -3393,6 +3497,9 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
}
}
+ if (Diags.isIgnored(diag::warn_profile_data_misexpect, SourceLocation()))
+ Res.FrontendOpts.LLVMArgs.push_back("-pgo-warn-misexpect");
+
LangOpts.FunctionAlignment =
getLastArgIntValue(Args, OPT_function_alignment, 0, Diags);
@@ -3440,6 +3547,7 @@ std::string CompilerInvocation::getModuleHash() const {
using llvm::hash_code;
using llvm::hash_value;
using llvm::hash_combine;
+ using llvm::hash_combine_range;
// Start the signature with the compiler version.
// FIXME: We'd rather use something more cryptographically sound than
@@ -3494,6 +3602,24 @@ std::string CompilerInvocation::getModuleHash() const {
hsOpts.ModulesValidateDiagnosticOptions);
code = hash_combine(code, hsOpts.ResourceDir);
+ if (hsOpts.ModulesStrictContextHash) {
+ hash_code SHPC = hash_combine_range(hsOpts.SystemHeaderPrefixes.begin(),
+ hsOpts.SystemHeaderPrefixes.end());
+ hash_code UEC = hash_combine_range(hsOpts.UserEntries.begin(),
+ hsOpts.UserEntries.end());
+ code = hash_combine(code, hsOpts.SystemHeaderPrefixes.size(), SHPC,
+ hsOpts.UserEntries.size(), UEC);
+
+ const DiagnosticOptions &diagOpts = getDiagnosticOpts();
+ #define DIAGOPT(Name, Bits, Default) \
+ code = hash_combine(code, diagOpts.Name);
+ #define ENUM_DIAGOPT(Name, Type, Bits, Default) \
+ code = hash_combine(code, diagOpts.get##Name());
+ #include "clang/Basic/DiagnosticOptions.def"
+ #undef DIAGOPT
+ #undef ENUM_DIAGOPT
+ }
+
// Extend the signature with the user build path.
code = hash_combine(code, hsOpts.ModuleUserBuildPath);
diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp
index b62416ffd9e7..ab62b633cda3 100644
--- a/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -24,14 +24,9 @@
using namespace clang;
using namespace llvm::opt;
-/// createInvocationFromCommandLine - Construct a compiler invocation object for
-/// a command line argument vector.
-///
-/// \return A CompilerInvocation, or 0 if none was built for the given
-/// argument vector.
std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
ArrayRef<const char *> ArgList, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
- IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, bool ShouldRecoverOnErorrs) {
if (!Diags.get()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
@@ -94,12 +89,9 @@ std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
}
const ArgStringList &CCArgs = Cmd.getArguments();
- auto CI = llvm::make_unique<CompilerInvocation>();
- if (!CompilerInvocation::CreateFromArgs(*CI,
- const_cast<const char **>(CCArgs.data()),
- const_cast<const char **>(CCArgs.data()) +
- CCArgs.size(),
- *Diags))
+ auto CI = std::make_unique<CompilerInvocation>();
+ if (!CompilerInvocation::CreateFromArgs(*CI, CCArgs, *Diags) &&
+ !ShouldRecoverOnErorrs)
return nullptr;
return CI;
}
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index 375eb91ae366..4bb0167bd597 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -46,20 +46,20 @@ struct DepCollectorPPCallbacks : public PPCallbacks {
// Dependency generation really does want to go all the way to the
// file entry for a source location to find out what is depended on.
// We do not want #line markers to affect dependency generation!
- const FileEntry *FE =
- SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(Loc)));
- if (!FE)
+ Optional<FileEntryRef> File =
+ SM.getFileEntryRefForID(SM.getFileID(SM.getExpansionLoc(Loc)));
+ if (!File)
return;
StringRef Filename =
- llvm::sys::path::remove_leading_dotslash(FE->getName());
+ llvm::sys::path::remove_leading_dotslash(File->getName());
DepCollector.maybeAddDependency(Filename, /*FromModule*/false,
isSystem(FileType),
/*IsModuleFile*/false, /*IsMissing*/false);
}
- void FileSkipped(const FileEntry &SkippedFile, const Token &FilenameTok,
+ void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,
SrcMgr::CharacteristicKind FileType) override {
StringRef Filename =
llvm::sys::path::remove_leading_dotslash(SkippedFile.getName());
@@ -83,7 +83,7 @@ struct DepCollectorPPCallbacks : public PPCallbacks {
}
void HasInclude(SourceLocation Loc, StringRef SpelledFilename, bool IsAngled,
- const FileEntry *File,
+ Optional<FileEntryRef> File,
SrcMgr::CharacteristicKind FileType) override {
if (!File)
return;
@@ -168,13 +168,13 @@ bool DependencyCollector::sawDependency(StringRef Filename, bool FromModule,
DependencyCollector::~DependencyCollector() { }
void DependencyCollector::attachToPreprocessor(Preprocessor &PP) {
- PP.addPPCallbacks(llvm::make_unique<DepCollectorPPCallbacks>(
+ PP.addPPCallbacks(std::make_unique<DepCollectorPPCallbacks>(
*this, PP.getSourceManager(), PP.getDiagnostics()));
PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks(
- llvm::make_unique<DepCollectorMMCallbacks>(*this));
+ std::make_unique<DepCollectorMMCallbacks>(*this));
}
void DependencyCollector::attachToASTReader(ASTReader &R) {
- R.addListener(llvm::make_unique<DepCollectorASTListener>(*this));
+ R.addListener(std::make_unique<DepCollectorASTListener>(*this));
}
DependencyFileGenerator::DependencyFileGenerator(
@@ -192,11 +192,6 @@ DependencyFileGenerator::DependencyFileGenerator(
}
void DependencyFileGenerator::attachToPreprocessor(Preprocessor &PP) {
- if (Targets.empty()) {
- PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT);
- return;
- }
-
// Disable the "file not found" diagnostic if the -MG option was given.
if (AddMissingHeaderDeps)
PP.SetSuppressIncludeNotFoundError(true);
@@ -316,7 +311,7 @@ void DependencyFileGenerator::outputDependencyFile(DiagnosticsEngine &Diags) {
}
std::error_code EC;
- llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
+ llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_Text);
if (EC) {
Diags.Report(diag::err_fe_error_opening) << OutputFile << EC.message();
return;
diff --git a/lib/Frontend/DependencyGraph.cpp b/lib/Frontend/DependencyGraph.cpp
index 90624323a000..ccf7a2785510 100644
--- a/lib/Frontend/DependencyGraph.cpp
+++ b/lib/Frontend/DependencyGraph.cpp
@@ -61,7 +61,7 @@ public:
void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
StringRef SysRoot) {
- PP.addPPCallbacks(llvm::make_unique<DependencyGraphCallback>(&PP, OutputFile,
+ PP.addPPCallbacks(std::make_unique<DependencyGraphCallback>(&PP, OutputFile,
SysRoot));
}
@@ -100,7 +100,7 @@ DependencyGraphCallback::writeNodeReference(raw_ostream &OS,
void DependencyGraphCallback::OutputGraphFile() {
std::error_code EC;
- llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
+ llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_Text);
if (EC) {
PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
<< EC.message();
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index d724bbce3749..b3b7976f8f3e 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -10,6 +10,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
+#include "clang/Basic/LangStandard.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
@@ -215,7 +216,7 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
Consumers.push_back(std::move(C));
}
- return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
+ return std::make_unique<MultiplexConsumer>(std::move(Consumers));
}
/// For preprocessed files, if the first line is the linemarker and specifies
@@ -370,7 +371,7 @@ static std::error_code collectModuleHeaderIncludes(
.Default(false))
continue;
- const FileEntry *Header = FileMgr.getFile(Dir->path());
+ auto Header = FileMgr.getFile(Dir->path());
// FIXME: This shouldn't happen unless there is a file system race. Is
// that worth diagnosing?
if (!Header)
@@ -378,7 +379,7 @@ static std::error_code collectModuleHeaderIncludes(
// If this header is marked 'unavailable' in this module, don't include
// it.
- if (ModMap.isHeaderUnavailableInModule(Header, Module))
+ if (ModMap.isHeaderUnavailableInModule(*Header, Module))
continue;
// Compute the relative path from the directory to this file.
@@ -392,7 +393,7 @@ static std::error_code collectModuleHeaderIncludes(
llvm::sys::path::append(RelativeHeader, *It);
// Include this header as part of the umbrella directory.
- Module->addTopHeader(Header);
+ Module->addTopHeader(*Header);
addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC);
}
@@ -481,7 +482,7 @@ static Module *prepareToBuildModule(CompilerInstance &CI,
// the module map, rather than adding it after the fact.
StringRef OriginalModuleMapName = CI.getFrontendOpts().OriginalModuleMap;
if (!OriginalModuleMapName.empty()) {
- auto *OriginalModuleMap =
+ auto OriginalModuleMap =
CI.getFileManager().getFile(OriginalModuleMapName,
/*openFile*/ true);
if (!OriginalModuleMap) {
@@ -489,11 +490,11 @@ static Module *prepareToBuildModule(CompilerInstance &CI,
<< OriginalModuleMapName;
return nullptr;
}
- if (OriginalModuleMap != CI.getSourceManager().getFileEntryForID(
+ if (*OriginalModuleMap != CI.getSourceManager().getFileEntryForID(
CI.getSourceManager().getMainFileID())) {
M->IsInferred = true;
CI.getPreprocessor().getHeaderSearchInfo().getModuleMap()
- .setInferredModuleAllowedBy(M, OriginalModuleMap);
+ .setInferredModuleAllowedBy(M, *OriginalModuleMap);
}
}
@@ -674,8 +675,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// Set up embedding for any specified files. Do this before we load any
// source files, including the primary module map for the compilation.
for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
- if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true))
- CI.getSourceManager().setFileIsTransient(FE);
+ if (auto FE = CI.getFileManager().getFile(F, /*openFile*/true))
+ CI.getSourceManager().setFileIsTransient(*FE);
else
CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F;
}
@@ -683,7 +684,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.getSourceManager().setAllFilesAreTransient(true);
// IR files bypass the rest of initialization.
- if (Input.getKind().getLanguage() == InputKind::LLVM_IR) {
+ if (Input.getKind().getLanguage() == Language::LLVM_IR) {
assert(hasIRSupport() &&
"This action does not have IR file support!");
@@ -709,10 +710,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
StringRef PCHInclude = PPOpts.ImplicitPCHInclude;
std::string SpecificModuleCachePath = CI.getSpecificModuleCachePath();
- if (const DirectoryEntry *PCHDir = FileMgr.getDirectory(PCHInclude)) {
+ if (auto PCHDir = FileMgr.getDirectory(PCHInclude)) {
std::error_code EC;
SmallString<128> DirNative;
- llvm::sys::path::native(PCHDir->getName(), DirNative);
+ llvm::sys::path::native((*PCHDir)->getName(), DirNative);
bool Found = false;
llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem();
for (llvm::vfs::directory_iterator Dir = FS.dir_begin(DirNative, EC),
@@ -792,9 +793,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// If we were asked to load any module map files, do so now.
for (const auto &Filename : CI.getFrontendOpts().ModuleMapFiles) {
- if (auto *File = CI.getFileManager().getFile(Filename))
+ if (auto File = CI.getFileManager().getFile(Filename))
CI.getPreprocessor().getHeaderSearchInfo().loadModuleMapFile(
- File, /*IsSystem*/false);
+ *File, /*IsSystem*/false);
else
CI.getDiagnostics().Report(diag::err_module_map_not_found) << Filename;
}
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index e37afae5332a..4d47c768ad3c 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -9,6 +9,7 @@
#include "clang/Frontend/FrontendActions.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangStandard.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
@@ -54,7 +55,7 @@ void EnsureSemaIsCreated(CompilerInstance &CI, FrontendAction &Action) {
std::unique_ptr<ASTConsumer>
InitOnlyAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
- return llvm::make_unique<ASTConsumer>();
+ return std::make_unique<ASTConsumer>();
}
void InitOnlyAction::ExecuteAction() {
@@ -108,7 +109,7 @@ GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
const auto &FrontendOpts = CI.getFrontendOpts();
auto Buffer = std::make_shared<PCHBuffer>();
std::vector<std::unique_ptr<ASTConsumer>> Consumers;
- Consumers.push_back(llvm::make_unique<PCHGenerator>(
+ Consumers.push_back(std::make_unique<PCHGenerator>(
CI.getPreprocessor(), CI.getModuleCache(), OutputFile, Sysroot, Buffer,
FrontendOpts.ModuleFileExtensions,
CI.getPreprocessorOpts().AllowPCHWithCompilerErrors,
@@ -116,7 +117,7 @@ GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
CI, InFile, OutputFile, std::move(OS), Buffer));
- return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
+ return std::make_unique<MultiplexConsumer>(std::move(Consumers));
}
bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI,
@@ -171,7 +172,7 @@ GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
auto Buffer = std::make_shared<PCHBuffer>();
std::vector<std::unique_ptr<ASTConsumer>> Consumers;
- Consumers.push_back(llvm::make_unique<PCHGenerator>(
+ Consumers.push_back(std::make_unique<PCHGenerator>(
CI.getPreprocessor(), CI.getModuleCache(), OutputFile, Sysroot, Buffer,
CI.getFrontendOpts().ModuleFileExtensions,
/*AllowASTWithErrors=*/false,
@@ -181,7 +182,7 @@ GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
+CI.getFrontendOpts().BuildingImplicitModule));
Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
CI, InFile, OutputFile, std::move(OS), Buffer));
- return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
+ return std::make_unique<MultiplexConsumer>(std::move(Consumers));
}
bool GenerateModuleFromModuleMapAction::BeginSourceFileAction(
@@ -286,15 +287,15 @@ bool GenerateHeaderModuleAction::BeginSourceFileAction(
SmallVector<Module::Header, 16> Headers;
for (StringRef Name : ModuleHeaders) {
const DirectoryLookup *CurDir = nullptr;
- const FileEntry *FE = HS.LookupFile(
- Name, SourceLocation(), /*Angled*/ false, nullptr, CurDir,
- None, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+ Optional<FileEntryRef> FE = HS.LookupFile(
+ Name, SourceLocation(), /*Angled*/ false, nullptr, CurDir, None,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
if (!FE) {
CI.getDiagnostics().Report(diag::err_module_header_file_not_found)
<< Name;
continue;
}
- Headers.push_back({Name, FE});
+ Headers.push_back({Name, &FE->getFileEntry()});
}
HS.getModuleMap().createHeaderModule(CI.getLangOpts().CurrentModule, Headers);
@@ -312,18 +313,18 @@ SyntaxOnlyAction::~SyntaxOnlyAction() {
std::unique_ptr<ASTConsumer>
SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
- return llvm::make_unique<ASTConsumer>();
+ return std::make_unique<ASTConsumer>();
}
std::unique_ptr<ASTConsumer>
DumpModuleInfoAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
- return llvm::make_unique<ASTConsumer>();
+ return std::make_unique<ASTConsumer>();
}
std::unique_ptr<ASTConsumer>
VerifyPCHAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
- return llvm::make_unique<ASTConsumer>();
+ return std::make_unique<ASTConsumer>();
}
void VerifyPCHAction::ExecuteAction() {
@@ -414,8 +415,14 @@ private:
return "DeclaringSpecialMember";
case CodeSynthesisContext::DefiningSynthesizedFunction:
return "DefiningSynthesizedFunction";
+ case CodeSynthesisContext::RewritingOperatorAsSpaceship:
+ return "RewritingOperatorAsSpaceship";
case CodeSynthesisContext::Memoization:
return "Memoization";
+ case CodeSynthesisContext::ConstraintsCheck:
+ return "ConstraintsCheck";
+ case CodeSynthesisContext::ConstraintSubstitution:
+ return "ConstraintSubstitution";
}
return "";
}
@@ -465,7 +472,7 @@ private:
std::unique_ptr<ASTConsumer>
TemplightDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
- return llvm::make_unique<ASTConsumer>();
+ return std::make_unique<ASTConsumer>();
}
void TemplightDumpAction::ExecuteAction() {
@@ -478,7 +485,7 @@ void TemplightDumpAction::ExecuteAction() {
EnsureSemaIsCreated(CI, *this);
CI.getSema().TemplateInstCallbacks.push_back(
- llvm::make_unique<DefaultTemplateInstCallback>());
+ std::make_unique<DefaultTemplateInstCallback>());
ASTFrontendAction::ExecuteAction();
}
@@ -695,7 +702,7 @@ void DumpModuleInfoAction::ExecuteAction() {
if (!OutputFileName.empty() && OutputFileName != "-") {
std::error_code EC;
OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str(), EC,
- llvm::sys::fs::F_Text));
+ llvm::sys::fs::OF_Text));
}
llvm::raw_ostream &Out = OutFile.get()? *OutFile.get() : llvm::outs();
@@ -832,19 +839,19 @@ void PrintPreprocessedAction::ExecuteAction() {
void PrintPreambleAction::ExecuteAction() {
switch (getCurrentFileKind().getLanguage()) {
- case InputKind::C:
- case InputKind::CXX:
- case InputKind::ObjC:
- case InputKind::ObjCXX:
- case InputKind::OpenCL:
- case InputKind::CUDA:
- case InputKind::HIP:
+ case Language::C:
+ case Language::CXX:
+ case Language::ObjC:
+ case Language::ObjCXX:
+ case Language::OpenCL:
+ case Language::CUDA:
+ case Language::HIP:
break;
- case InputKind::Unknown:
- case InputKind::Asm:
- case InputKind::LLVM_IR:
- case InputKind::RenderScript:
+ case Language::Unknown:
+ case Language::Asm:
+ case Language::LLVM_IR:
+ case Language::RenderScript:
// We can't do anything with these.
return;
}
@@ -927,7 +934,7 @@ void PrintDependencyDirectivesSourceMinimizerAction::ExecuteAction() {
// 'expected' comments.
if (CI.getDiagnosticOpts().VerifyDiagnostics) {
// Make sure we don't emit new diagnostics!
- CI.getDiagnostics().setSuppressAllDiagnostics();
+ CI.getDiagnostics().setSuppressAllDiagnostics(true);
Preprocessor &PP = getCompilerInstance().getPreprocessor();
PP.EnterMainSourceFile();
Token Tok;
diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp
index 6ccb2c395604..5c1fbf889c23 100644
--- a/lib/Frontend/FrontendOptions.cpp
+++ b/lib/Frontend/FrontendOptions.cpp
@@ -7,28 +7,29 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/FrontendOptions.h"
+#include "clang/Basic/LangStandard.h"
#include "llvm/ADT/StringSwitch.h"
using namespace clang;
InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) {
return llvm::StringSwitch<InputKind>(Extension)
- .Cases("ast", "pcm", InputKind(InputKind::Unknown, InputKind::Precompiled))
- .Case("c", InputKind::C)
- .Cases("S", "s", InputKind::Asm)
- .Case("i", InputKind(InputKind::C).getPreprocessed())
- .Case("ii", InputKind(InputKind::CXX).getPreprocessed())
- .Case("cui", InputKind(InputKind::CUDA).getPreprocessed())
- .Case("m", InputKind::ObjC)
- .Case("mi", InputKind(InputKind::ObjC).getPreprocessed())
- .Cases("mm", "M", InputKind::ObjCXX)
- .Case("mii", InputKind(InputKind::ObjCXX).getPreprocessed())
- .Cases("C", "cc", "cp", InputKind::CXX)
- .Cases("cpp", "CPP", "c++", "cxx", "hpp", InputKind::CXX)
- .Case("cppm", InputKind::CXX)
- .Case("iim", InputKind(InputKind::CXX).getPreprocessed())
- .Case("cl", InputKind::OpenCL)
- .Case("cu", InputKind::CUDA)
- .Cases("ll", "bc", InputKind::LLVM_IR)
- .Default(InputKind::Unknown);
+ .Cases("ast", "pcm", InputKind(Language::Unknown, InputKind::Precompiled))
+ .Case("c", Language::C)
+ .Cases("S", "s", Language::Asm)
+ .Case("i", InputKind(Language::C).getPreprocessed())
+ .Case("ii", InputKind(Language::CXX).getPreprocessed())
+ .Case("cui", InputKind(Language::CUDA).getPreprocessed())
+ .Case("m", Language::ObjC)
+ .Case("mi", InputKind(Language::ObjC).getPreprocessed())
+ .Cases("mm", "M", Language::ObjCXX)
+ .Case("mii", InputKind(Language::ObjCXX).getPreprocessed())
+ .Cases("C", "cc", "cp", Language::CXX)
+ .Cases("cpp", "CPP", "c++", "cxx", "hpp", Language::CXX)
+ .Case("cppm", Language::CXX)
+ .Case("iim", InputKind(Language::CXX).getPreprocessed())
+ .Case("cl", Language::OpenCL)
+ .Case("cu", Language::CUDA)
+ .Cases("ll", "bc", Language::LLVM_IR)
+ .Default(Language::Unknown);
}
diff --git a/lib/Frontend/HeaderIncludeGen.cpp b/lib/Frontend/HeaderIncludeGen.cpp
index d60f5333bf5b..5f91157816b0 100644
--- a/lib/Frontend/HeaderIncludeGen.cpp
+++ b/lib/Frontend/HeaderIncludeGen.cpp
@@ -100,7 +100,8 @@ void clang::AttachHeaderIncludeGen(Preprocessor &PP,
if (!OutputPath.empty()) {
std::error_code EC;
llvm::raw_fd_ostream *OS = new llvm::raw_fd_ostream(
- OutputPath.str(), EC, llvm::sys::fs::F_Append | llvm::sys::fs::F_Text);
+ OutputPath.str(), EC,
+ llvm::sys::fs::OF_Append | llvm::sys::fs::OF_Text);
if (EC) {
PP.getDiagnostics().Report(clang::diag::warn_fe_cc_print_header_failure)
<< EC.message();
@@ -119,7 +120,7 @@ void clang::AttachHeaderIncludeGen(Preprocessor &PP,
// the GNU way to generate rules is -M / -MM / -MD / -MMD.
for (const auto &Header : DepOpts.ExtraDeps)
PrintHeaderInfo(OutputFile, Header, ShowDepth, 2, MSStyle);
- PP.addPPCallbacks(llvm::make_unique<HeaderIncludesCallback>(
+ PP.addPPCallbacks(std::make_unique<HeaderIncludesCallback>(
&PP, ShowAllHeaders, OutputFile, DepOpts, OwnsOutputFile, ShowDepth,
MSStyle));
}
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index d65d13489dc4..5d877ee9c0d7 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -137,6 +137,13 @@ bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
SmallString<256> MappedPathStorage;
StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
+ // If use system headers while cross-compiling, emit the warning.
+ if (HasSysroot && (MappedPathStr.startswith("/usr/include") ||
+ MappedPathStr.startswith("/usr/local/include"))) {
+ Headers.getDiags().Report(diag::warn_poison_system_directories)
+ << MappedPathStr;
+ }
+
// Compute the DirectoryLookup type.
SrcMgr::CharacteristicKind Type;
if (Group == Quoted || Group == Angled || Group == IndexHeaderMap) {
@@ -148,17 +155,17 @@ bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
}
// If the directory exists, add it.
- if (const DirectoryEntry *DE = FM.getDirectory(MappedPathStr)) {
+ if (auto DE = FM.getOptionalDirectoryRef(MappedPathStr)) {
IncludePath.push_back(
- std::make_pair(Group, DirectoryLookup(DE, Type, isFramework)));
+ std::make_pair(Group, DirectoryLookup(*DE, Type, isFramework)));
return true;
}
// Check to see if this is an apple-style headermap (which are not allowed to
// be frameworks).
if (!isFramework) {
- if (const FileEntry *FE = FM.getFile(MappedPathStr)) {
- if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) {
+ if (auto FE = FM.getFile(MappedPathStr)) {
+ if (const HeaderMap *HM = Headers.CreateHeaderMap(*FE)) {
// It is a headermap, add it to the search path.
IncludePath.push_back(
std::make_pair(Group,
@@ -636,8 +643,8 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
// Set up the builtin include directory in the module map.
SmallString<128> P = StringRef(HSOpts.ResourceDir);
llvm::sys::path::append(P, "include");
- if (const DirectoryEntry *Dir = HS.getFileMgr().getDirectory(P))
- HS.getModuleMap().setBuiltinIncludeDir(Dir);
+ if (auto Dir = HS.getFileMgr().getDirectory(P))
+ HS.getModuleMap().setBuiltinIncludeDir(*Dir);
}
Init.Realize(Lang);
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 3906e2ae1b98..c27c33c530f6 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -24,6 +24,7 @@
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/APFloat.h"
+#include "llvm/IR/DataLayout.h"
using namespace clang;
static bool MacroBodyEndsInBackslash(StringRef MacroBody) {
@@ -437,17 +438,17 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
default:
llvm_unreachable("Unsupported OpenCL version");
}
- Builder.defineMacro("CL_VERSION_1_0", "100");
- Builder.defineMacro("CL_VERSION_1_1", "110");
- Builder.defineMacro("CL_VERSION_1_2", "120");
- Builder.defineMacro("CL_VERSION_2_0", "200");
+ }
+ Builder.defineMacro("CL_VERSION_1_0", "100");
+ Builder.defineMacro("CL_VERSION_1_1", "110");
+ Builder.defineMacro("CL_VERSION_1_2", "120");
+ Builder.defineMacro("CL_VERSION_2_0", "200");
- if (TI.isLittleEndian())
- Builder.defineMacro("__ENDIAN_LITTLE__");
+ if (TI.isLittleEndian())
+ Builder.defineMacro("__ENDIAN_LITTLE__");
- if (LangOpts.FastRelaxedMath)
- Builder.defineMacro("__FAST_RELAXED_MATH__");
- }
+ if (LangOpts.FastRelaxedMath)
+ Builder.defineMacro("__FAST_RELAXED_MATH__");
}
// Not "standard" per se, but available even with the -undef flag.
if (LangOpts.AsmPreprocessor)
@@ -480,6 +481,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_user_defined_literals", "200809L");
Builder.defineMacro("__cpp_lambdas", "200907L");
Builder.defineMacro("__cpp_constexpr",
+ LangOpts.CPlusPlus2a ? "201907L" :
LangOpts.CPlusPlus17 ? "201603L" :
LangOpts.CPlusPlus14 ? "201304L" : "200704");
Builder.defineMacro("__cpp_range_based_for",
@@ -540,8 +542,11 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_template_template_args", "201611L");
// C++20 features.
- if (LangOpts.CPlusPlus2a)
+ if (LangOpts.CPlusPlus2a) {
Builder.defineMacro("__cpp_conditional_explicit", "201806L");
+ Builder.defineMacro("__cpp_constexpr_dynamic_alloc", "201907L");
+ Builder.defineMacro("__cpp_constinit", "201907L");
+ }
if (LangOpts.Char8)
Builder.defineMacro("__cpp_char8_t", "201811L");
Builder.defineMacro("__cpp_impl_destroying_delete", "201806L");
@@ -556,6 +561,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
static void InitializePredefinedMacros(const TargetInfo &TI,
const LangOptions &LangOpts,
const FrontendOptions &FEOpts,
+ const PreprocessorOptions &PPOpts,
MacroBuilder &Builder) {
// Compiler version introspection macros.
Builder.defineMacro("__llvm__"); // LLVM Backend
@@ -570,13 +576,22 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("__clang_version__",
"\"" CLANG_VERSION_STRING " "
+ getClangFullRepositoryVersion() + "\"");
- if (!LangOpts.MSVCCompat) {
- // 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");
+
+ if (LangOpts.GNUCVersion != 0) {
+ // Major, minor, patch, are given two decimal places each, so 4.2.1 becomes
+ // 40201.
+ unsigned GNUCMajor = LangOpts.GNUCVersion / 100 / 100;
+ unsigned GNUCMinor = LangOpts.GNUCVersion / 100 % 100;
+ unsigned GNUCPatch = LangOpts.GNUCVersion % 100;
+ Builder.defineMacro("__GNUC__", Twine(GNUCMajor));
+ Builder.defineMacro("__GNUC_MINOR__", Twine(GNUCMinor));
+ Builder.defineMacro("__GNUC_PATCHLEVEL__", Twine(GNUCPatch));
Builder.defineMacro("__GXX_ABI_VERSION", "1002");
+
+ if (LangOpts.CPlusPlus) {
+ Builder.defineMacro("__GNUG__", Twine(GNUCMajor));
+ Builder.defineMacro("__GXX_WEAK__");
+ }
}
// Define macros for the C11 / C++11 memory orderings
@@ -615,7 +630,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (!LangOpts.GNUMode && !LangOpts.MSVCCompat)
Builder.defineMacro("__STRICT_ANSI__");
- if (!LangOpts.MSVCCompat && LangOpts.CPlusPlus11)
+ if (LangOpts.GNUCVersion && LangOpts.CPlusPlus11)
Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__");
if (LangOpts.ObjC) {
@@ -695,7 +710,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (!LangOpts.MSVCCompat && LangOpts.Exceptions)
Builder.defineMacro("__EXCEPTIONS");
- if (!LangOpts.MSVCCompat && LangOpts.RTTI)
+ if (LangOpts.GNUCVersion && LangOpts.RTTI)
Builder.defineMacro("__GXX_RTTI");
if (LangOpts.SjLjExceptions)
@@ -709,11 +724,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.Deprecated)
Builder.defineMacro("__DEPRECATED");
- if (!LangOpts.MSVCCompat && LangOpts.CPlusPlus) {
- Builder.defineMacro("__GNUG__", "4");
- Builder.defineMacro("__GXX_WEAK__");
+ if (!LangOpts.MSVCCompat && LangOpts.CPlusPlus)
Builder.defineMacro("__private_extern__", "extern");
- }
if (LangOpts.MicrosoftExt) {
if (LangOpts.WChar) {
@@ -923,7 +935,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
else
Builder.defineMacro("__FINITE_MATH_ONLY__", "0");
- if (!LangOpts.MSVCCompat) {
+ if (LangOpts.GNUCVersion) {
if (LangOpts.GNUInline || LangOpts.CPlusPlus)
Builder.defineMacro("__GNUC_GNU_INLINE__");
else
@@ -960,7 +972,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
#undef DEFINE_LOCK_FREE_MACRO
};
addLockFreeMacros("__CLANG_ATOMIC_");
- if (!LangOpts.MSVCCompat)
+ if (LangOpts.GNUCVersion)
addLockFreeMacros("__GCC_ATOMIC_");
if (LangOpts.NoInlineDefine)
@@ -987,8 +999,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
Builder.defineMacro("__SSP_ALL__", "3");
- // Define a macro that exists only when using the static analyzer.
- if (FEOpts.ProgramAction == frontend::RunAnalysis)
+ if (PPOpts.SetUpStaticAnalyzer)
Builder.defineMacro("__clang_analyzer__");
if (LangOpts.FastRelaxedMath)
@@ -1032,15 +1043,18 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
switch (LangOpts.OpenMP) {
case 0:
break;
+ case 31:
+ Builder.defineMacro("_OPENMP", "201107");
+ break;
case 40:
Builder.defineMacro("_OPENMP", "201307");
break;
- case 45:
- Builder.defineMacro("_OPENMP", "201511");
+ case 50:
+ Builder.defineMacro("_OPENMP", "201811");
break;
default:
- // Default version is OpenMP 3.1
- Builder.defineMacro("_OPENMP", "201107");
+ // Default version is OpenMP 4.5
+ Builder.defineMacro("_OPENMP", "201511");
break;
}
}
@@ -1112,9 +1126,10 @@ void clang::InitializePreprocessor(
// macros. This is not the right way to handle this.
if ((LangOpts.CUDA || LangOpts.OpenMPIsDevice) && PP.getAuxTargetInfo())
InitializePredefinedMacros(*PP.getAuxTargetInfo(), LangOpts, FEOpts,
- Builder);
+ PP.getPreprocessorOpts(), Builder);
- InitializePredefinedMacros(PP.getTargetInfo(), LangOpts, FEOpts, Builder);
+ InitializePredefinedMacros(PP.getTargetInfo(), LangOpts, FEOpts,
+ PP.getPreprocessorOpts(), Builder);
// Install definitions to make Objective-C++ ARC work well with various
// C++ Standard Library implementations.
diff --git a/lib/Frontend/InterfaceStubFunctionsConsumer.cpp b/lib/Frontend/InterfaceStubFunctionsConsumer.cpp
index fbba9ae4d6a7..0b28b78de3b1 100644
--- a/lib/Frontend/InterfaceStubFunctionsConsumer.cpp
+++ b/lib/Frontend/InterfaceStubFunctionsConsumer.cpp
@@ -15,6 +15,7 @@
using namespace clang;
+namespace {
class InterfaceStubFunctionsConsumer : public ASTConsumer {
CompilerInstance &Instance;
StringRef InFile;
@@ -176,6 +177,10 @@ class InterfaceStubFunctionsConsumer : public ASTConsumer {
HandleTemplateSpecializations(*cast<FunctionTemplateDecl>(ND), Symbols,
RDO);
return true;
+ case Decl::Kind::Record:
+ case Decl::Kind::Typedef:
+ case Decl::Kind::Enum:
+ case Decl::Kind::EnumConstant:
case Decl::Kind::TemplateTypeParm:
return true;
case Decl::Kind::Var:
@@ -246,92 +251,27 @@ public:
for (const NamedDecl *ND : v.NamedDecls)
HandleNamedDecl(ND, Symbols, FromTU);
- auto writeIfoYaml = [this](const llvm::Triple &T,
- const MangledSymbols &Symbols,
- const ASTContext &context, StringRef Format,
- raw_ostream &OS) -> void {
- OS << "--- !" << Format << "\n";
- OS << "FileHeader:\n";
- OS << " Class: ELFCLASS";
- OS << (T.isArch64Bit() ? "64" : "32");
- OS << "\n";
- OS << " Data: ELFDATA2";
- OS << (T.isLittleEndian() ? "LSB" : "MSB");
- OS << "\n";
- OS << " Type: ET_REL\n";
- OS << " Machine: "
- << llvm::StringSwitch<llvm::StringRef>(T.getArchName())
- .Case("x86_64", "EM_X86_64")
- .Case("i386", "EM_386")
- .Case("i686", "EM_386")
- .Case("aarch64", "EM_AARCH64")
- .Case("amdgcn", "EM_AMDGPU")
- .Case("r600", "EM_AMDGPU")
- .Case("arm", "EM_ARM")
- .Case("thumb", "EM_ARM")
- .Case("avr", "EM_AVR")
- .Case("mips", "EM_MIPS")
- .Case("mipsel", "EM_MIPS")
- .Case("mips64", "EM_MIPS")
- .Case("mips64el", "EM_MIPS")
- .Case("msp430", "EM_MSP430")
- .Case("ppc", "EM_PPC")
- .Case("ppc64", "EM_PPC64")
- .Case("ppc64le", "EM_PPC64")
- .Case("x86", T.isOSIAMCU() ? "EM_IAMCU" : "EM_386")
- .Case("x86_64", "EM_X86_64")
- .Default("EM_NONE")
- << "\nSymbols:\n";
- for (const auto &E : Symbols) {
- const MangledSymbol &Symbol = E.second;
- for (auto Name : Symbol.Names) {
- OS << " - Name: "
- << (Symbol.ParentName.empty() || Instance.getLangOpts().CPlusPlus
- ? ""
- : (Symbol.ParentName + "."))
- << Name << "\n"
- << " Type: STT_";
- switch (Symbol.Type) {
- default:
- case llvm::ELF::STT_NOTYPE:
- OS << "NOTYPE";
- break;
- case llvm::ELF::STT_OBJECT:
- OS << "OBJECT";
- break;
- case llvm::ELF::STT_FUNC:
- OS << "FUNC";
- break;
- }
- OS << "\n Binding: STB_"
- << ((Symbol.Binding == llvm::ELF::STB_WEAK) ? "WEAK" : "GLOBAL")
- << "\n";
- }
- }
- OS << "...\n";
- OS.flush();
- };
-
- auto writeIfoElfAbiYaml =
+ auto writeIfsV1 =
[this](const llvm::Triple &T, const MangledSymbols &Symbols,
const ASTContext &context, StringRef Format,
raw_ostream &OS) -> void {
OS << "--- !" << Format << "\n";
- OS << "TbeVersion: 1.0\n";
- OS << "Arch: " << T.getArchName() << "\n";
+ OS << "IfsVersion: 1.0\n";
+ OS << "Triple: " << T.str() << "\n";
+ OS << "ObjectFileFormat: " << "ELF" << "\n"; // TODO: For now, just ELF.
OS << "Symbols:\n";
for (const auto &E : Symbols) {
const MangledSymbol &Symbol = E.second;
for (auto Name : Symbol.Names) {
- OS << " "
+ OS << " \""
<< (Symbol.ParentName.empty() || Instance.getLangOpts().CPlusPlus
? ""
: (Symbol.ParentName + "."))
- << Name << ": { Type: ";
+ << Name << "\" : { Type: ";
switch (Symbol.Type) {
default:
llvm_unreachable(
- "clang -emit-iterface-stubs: Unexpected symbol type.");
+ "clang -emit-interface-stubs: Unexpected symbol type.");
case llvm::ELF::STT_NOTYPE:
OS << "NoType";
break;
@@ -354,25 +294,15 @@ public:
OS.flush();
};
- if (Format == "experimental-yaml-elf-v1")
- writeIfoYaml(Instance.getTarget().getTriple(), Symbols, context, Format,
- *OS);
- else
- writeIfoElfAbiYaml(Instance.getTarget().getTriple(), Symbols, context,
- Format, *OS);
+ assert(Format == "experimental-ifs-v1" && "Unexpected IFS Format.");
+ writeIfsV1(Instance.getTarget().getTriple(), Symbols, context, Format, *OS);
}
};
+} // namespace
std::unique_ptr<ASTConsumer>
-GenerateInterfaceYAMLExpV1Action::CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) {
- return llvm::make_unique<InterfaceStubFunctionsConsumer>(
- CI, InFile, "experimental-yaml-elf-v1");
-}
-
-std::unique_ptr<ASTConsumer>
-GenerateInterfaceTBEExpV1Action::CreateASTConsumer(CompilerInstance &CI,
+GenerateInterfaceIfsExpV1Action::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
- return llvm::make_unique<InterfaceStubFunctionsConsumer>(
- CI, InFile, "experimental-tapi-elf-v1");
+ return std::make_unique<InterfaceStubFunctionsConsumer>(
+ CI, InFile, "experimental-ifs-v1");
}
diff --git a/lib/Frontend/ModuleDependencyCollector.cpp b/lib/Frontend/ModuleDependencyCollector.cpp
index c1d8c0d9eb24..fd22433d31bd 100644
--- a/lib/Frontend/ModuleDependencyCollector.cpp
+++ b/lib/Frontend/ModuleDependencyCollector.cpp
@@ -99,14 +99,14 @@ struct ModuleDependencyMMCallbacks : public ModuleMapCallbacks {
}
void ModuleDependencyCollector::attachToASTReader(ASTReader &R) {
- R.addListener(llvm::make_unique<ModuleDependencyListener>(*this));
+ R.addListener(std::make_unique<ModuleDependencyListener>(*this));
}
void ModuleDependencyCollector::attachToPreprocessor(Preprocessor &PP) {
- PP.addPPCallbacks(llvm::make_unique<ModuleDependencyPPCallbacks>(
+ PP.addPPCallbacks(std::make_unique<ModuleDependencyPPCallbacks>(
*this, PP.getSourceManager()));
PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks(
- llvm::make_unique<ModuleDependencyMMCallbacks>(*this));
+ std::make_unique<ModuleDependencyMMCallbacks>(*this));
}
static bool isCaseSensitivePath(StringRef Path) {
@@ -148,7 +148,7 @@ void ModuleDependencyCollector::writeFileMap() {
std::error_code EC;
SmallString<256> YAMLPath = VFSDir;
llvm::sys::path::append(YAMLPath, "vfs.yaml");
- llvm::raw_fd_ostream OS(YAMLPath, EC, llvm::sys::fs::F_Text);
+ llvm::raw_fd_ostream OS(YAMLPath, EC, llvm::sys::fs::OF_Text);
if (EC) {
HasErrors = true;
return;
diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp
index ed7028769d34..04e896296c95 100644
--- a/lib/Frontend/MultiplexConsumer.cpp
+++ b/lib/Frontend/MultiplexConsumer.cpp
@@ -249,11 +249,11 @@ MultiplexConsumer::MultiplexConsumer(
}
if (!mutationListeners.empty()) {
MutationListener =
- llvm::make_unique<MultiplexASTMutationListener>(mutationListeners);
+ std::make_unique<MultiplexASTMutationListener>(mutationListeners);
}
if (!serializationListeners.empty()) {
DeserializationListener =
- llvm::make_unique<MultiplexASTDeserializationListener>(
+ std::make_unique<MultiplexASTDeserializationListener>(
serializationListeners);
}
}
diff --git a/lib/Frontend/PrecompiledPreamble.cpp b/lib/Frontend/PrecompiledPreamble.cpp
index 276a9676eaa9..ced32c670288 100644
--- a/lib/Frontend/PrecompiledPreamble.cpp
+++ b/lib/Frontend/PrecompiledPreamble.cpp
@@ -12,6 +12,7 @@
#include "clang/Frontend/PrecompiledPreamble.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/LangStandard.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
@@ -26,11 +27,10 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Mutex.h"
-#include "llvm/Support/MutexGuard.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <limits>
+#include <mutex>
#include <utility>
using namespace clang;
@@ -95,7 +95,7 @@ public:
void removeFile(StringRef File);
private:
- llvm::sys::SmartMutex<false> Mutex;
+ std::mutex Mutex;
llvm::StringSet<> Files;
};
@@ -105,20 +105,20 @@ TemporaryFiles &TemporaryFiles::getInstance() {
}
TemporaryFiles::~TemporaryFiles() {
- llvm::MutexGuard Guard(Mutex);
+ std::lock_guard<std::mutex> Guard(Mutex);
for (const auto &File : Files)
llvm::sys::fs::remove(File.getKey());
}
void TemporaryFiles::addFile(StringRef File) {
- llvm::MutexGuard Guard(Mutex);
+ std::lock_guard<std::mutex> Guard(Mutex);
auto IsInserted = Files.insert(File).second;
(void)IsInserted;
assert(IsInserted && "File has already been added");
}
void TemporaryFiles::removeFile(StringRef File) {
- llvm::MutexGuard Guard(Mutex);
+ std::lock_guard<std::mutex> Guard(Mutex);
auto WasPresent = Files.erase(File);
(void)WasPresent;
assert(WasPresent && "File was not tracked");
@@ -202,7 +202,7 @@ PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
std::unique_ptr<llvm::raw_ostream> OS;
if (InMemStorage) {
- OS = llvm::make_unique<llvm::raw_string_ostream>(*InMemStorage);
+ OS = std::make_unique<llvm::raw_string_ostream>(*InMemStorage);
} else {
std::string OutputFile;
OS = GeneratePCHAction::CreateOutputFile(CI, InFile, OutputFile);
@@ -213,7 +213,7 @@ PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
if (!CI.getFrontendOpts().RelocatablePCH)
Sysroot.clear();
- return llvm::make_unique<PrecompilePreambleConsumer>(
+ return std::make_unique<PrecompilePreambleConsumer>(
*this, CI.getPreprocessor(), CI.getModuleCache(), Sysroot, std::move(OS));
}
@@ -303,7 +303,7 @@ llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
Clang->getFrontendOpts().Inputs[0].getKind().getFormat() !=
InputKind::Source ||
Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() ==
- InputKind::LLVM_IR) {
+ Language::LLVM_IR) {
return BuildPreambleError::BadInputs;
}
@@ -369,9 +369,11 @@ llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
SourceManager &SourceMgr = Clang->getSourceManager();
for (auto &Filename : PreambleDepCollector->getDependencies()) {
- const FileEntry *File = Clang->getFileManager().getFile(Filename);
- if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
+ auto FileOrErr = Clang->getFileManager().getFile(Filename);
+ if (!FileOrErr ||
+ *FileOrErr == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()))
continue;
+ auto File = *FileOrErr;
if (time_t ModTime = File->getModificationTime()) {
FilesInPreamble[File->getName()] =
PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(),
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 732edacffbe3..24ea1ccba207 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -675,7 +675,7 @@ struct UnknownPragmaHandler : public PragmaHandler {
if (ShouldExpandTokens) {
// The first token does not have expanded macros. Expand them, if
// required.
- auto Toks = llvm::make_unique<Token[]>(1);
+ auto Toks = std::make_unique<Token[]>(1);
Toks[0] = PragmaTok;
PP.EnterTokenStream(std::move(Toks), /*NumToks=*/1,
/*DisableMacroExpansion=*/false,
diff --git a/lib/Frontend/Rewrite/FixItRewriter.cpp b/lib/Frontend/Rewrite/FixItRewriter.cpp
index 667b9f0469f7..0217b3385a51 100644
--- a/lib/Frontend/Rewrite/FixItRewriter.cpp
+++ b/lib/Frontend/Rewrite/FixItRewriter.cpp
@@ -101,7 +101,7 @@ bool FixItRewriter::WriteFixedFiles(
if (fd != -1) {
OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
} else {
- OS.reset(new llvm::raw_fd_ostream(Filename, EC, llvm::sys::fs::F_None));
+ OS.reset(new llvm::raw_fd_ostream(Filename, EC, llvm::sys::fs::OF_None));
}
if (EC) {
Diags.Report(clang::diag::err_fe_unable_to_open_output) << Filename
diff --git a/lib/Frontend/Rewrite/FrontendActions.cpp b/lib/Frontend/Rewrite/FrontendActions.cpp
index 0f1a0584c72b..549b86edebcd 100644
--- a/lib/Frontend/Rewrite/FrontendActions.cpp
+++ b/lib/Frontend/Rewrite/FrontendActions.cpp
@@ -9,6 +9,7 @@
#include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/LangStandard.h"
#include "clang/Config/config.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
@@ -49,7 +50,7 @@ FixItAction::~FixItAction() {}
std::unique_ptr<ASTConsumer>
FixItAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
- return llvm::make_unique<ASTConsumer>();
+ return std::make_unique<ASTConsumer>();
}
namespace {
@@ -211,16 +212,16 @@ public:
void visitModuleFile(StringRef Filename,
serialization::ModuleKind Kind) override {
- auto *File = CI.getFileManager().getFile(Filename);
+ auto File = CI.getFileManager().getFile(Filename);
assert(File && "missing file for loaded module?");
// Only rewrite each module file once.
- if (!Rewritten.insert(File).second)
+ if (!Rewritten.insert(*File).second)
return;
serialization::ModuleFile *MF =
- CI.getModuleManager()->getModuleManager().lookup(File);
- assert(File && "missing module file for loaded module?");
+ CI.getModuleManager()->getModuleManager().lookup(*File);
+ assert(MF && "missing module file for loaded module?");
// Not interested in PCH / preambles.
if (!MF->isModule())
@@ -250,7 +251,7 @@ public:
Instance.getFrontendOpts().DisableFree = false;
Instance.getFrontendOpts().Inputs.clear();
Instance.getFrontendOpts().Inputs.emplace_back(
- Filename, InputKind(InputKind::Unknown, InputKind::Precompiled));
+ Filename, InputKind(Language::Unknown, InputKind::Precompiled));
Instance.getFrontendOpts().ModuleFiles.clear();
Instance.getFrontendOpts().ModuleMapFiles.clear();
// Don't recursively rewrite imports. We handle them all at the top level.
@@ -294,7 +295,7 @@ bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) {
if (CI.getPreprocessorOutputOpts().RewriteImports) {
CI.createModuleManager();
CI.getModuleManager()->addListener(
- llvm::make_unique<RewriteImportsListener>(CI, OutputStream));
+ std::make_unique<RewriteImportsListener>(CI, OutputStream));
}
return true;
diff --git a/lib/Frontend/Rewrite/HTMLPrint.cpp b/lib/Frontend/Rewrite/HTMLPrint.cpp
index a5b36bc7856c..982e56cebbca 100644
--- a/lib/Frontend/Rewrite/HTMLPrint.cpp
+++ b/lib/Frontend/Rewrite/HTMLPrint.cpp
@@ -48,7 +48,7 @@ namespace {
std::unique_ptr<ASTConsumer>
clang::CreateHTMLPrinter(std::unique_ptr<raw_ostream> OS, Preprocessor &PP,
bool SyntaxHighlight, bool HighlightMacros) {
- return llvm::make_unique<HTMLPrinter>(std::move(OS), PP, SyntaxHighlight,
+ return std::make_unique<HTMLPrinter>(std::move(OS), PP, SyntaxHighlight,
HighlightMacros);
}
diff --git a/lib/Frontend/Rewrite/InclusionRewriter.cpp b/lib/Frontend/Rewrite/InclusionRewriter.cpp
index cb4e773aca87..dcf645f67f2f 100644
--- a/lib/Frontend/Rewrite/InclusionRewriter.cpp
+++ b/lib/Frontend/Rewrite/InclusionRewriter.cpp
@@ -49,6 +49,8 @@ class InclusionRewriter : public PPCallbacks {
std::map<unsigned, const Module *> ModuleIncludes;
/// Tracks where inclusions that enter modules (in a module build) are found.
std::map<unsigned, const Module *> ModuleEntryIncludes;
+ /// Tracks where #if and #elif directives get evaluated and whether to true.
+ std::map<unsigned, bool> IfConditions;
/// Used transitively for building up the FileIncludes mapping over the
/// various \c PPCallbacks callbacks.
SourceLocation LastInclusionLocation;
@@ -70,7 +72,7 @@ private:
void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
FileID PrevFID) override;
- void FileSkipped(const FileEntry &SkippedFile, const Token &FilenameTok,
+ void FileSkipped(const FileEntryRef &SkippedFile, const Token &FilenameTok,
SrcMgr::CharacteristicKind FileType) override;
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled,
@@ -78,6 +80,10 @@ private:
StringRef SearchPath, StringRef RelativePath,
const Module *Imported,
SrcMgr::CharacteristicKind FileType) override;
+ void If(SourceLocation Loc, SourceRange ConditionRange,
+ ConditionValueKind ConditionValue) override;
+ void Elif(SourceLocation Loc, SourceRange ConditionRange,
+ ConditionValueKind ConditionValue, SourceLocation IfLoc) override;
void WriteLineInfo(StringRef Filename, int Line,
SrcMgr::CharacteristicKind FileType,
StringRef Extra = StringRef());
@@ -89,12 +95,10 @@ private:
void CommentOutDirective(Lexer &DirectivesLex, const Token &StartToken,
const MemoryBuffer &FromFile, StringRef EOL,
unsigned &NextToWrite, int &Lines);
- bool HandleHasInclude(FileID FileId, Lexer &RawLex,
- const DirectoryLookup *Lookup, Token &Tok,
- bool &FileExists);
const IncludedFile *FindIncludeAtLocation(SourceLocation Loc) const;
const Module *FindModuleAtLocation(SourceLocation Loc) const;
const Module *FindEnteredModule(SourceLocation Loc) const;
+ bool IsIfAtLocationTrue(SourceLocation Loc) const;
StringRef NextIdentifierName(Lexer &RawLex, Token &RawToken);
};
@@ -169,8 +173,8 @@ void InclusionRewriter::FileChanged(SourceLocation Loc,
/// Called whenever an inclusion is skipped due to canonical header protection
/// macros.
-void InclusionRewriter::FileSkipped(const FileEntry &/*SkippedFile*/,
- const Token &/*FilenameTok*/,
+void InclusionRewriter::FileSkipped(const FileEntryRef & /*SkippedFile*/,
+ const Token & /*FilenameTok*/,
SrcMgr::CharacteristicKind /*FileType*/) {
assert(LastInclusionLocation.isValid() &&
"A file, that wasn't found via an inclusion directive, was skipped");
@@ -203,6 +207,23 @@ void InclusionRewriter::InclusionDirective(SourceLocation HashLoc,
LastInclusionLocation = HashLoc;
}
+void InclusionRewriter::If(SourceLocation Loc, SourceRange ConditionRange,
+ ConditionValueKind ConditionValue) {
+ auto P = IfConditions.insert(
+ std::make_pair(Loc.getRawEncoding(), ConditionValue == CVK_True));
+ (void)P;
+ assert(P.second && "Unexpected revisitation of the same if directive");
+}
+
+void InclusionRewriter::Elif(SourceLocation Loc, SourceRange ConditionRange,
+ ConditionValueKind ConditionValue,
+ SourceLocation IfLoc) {
+ auto P = IfConditions.insert(
+ std::make_pair(Loc.getRawEncoding(), ConditionValue == CVK_True));
+ (void)P;
+ assert(P.second && "Unexpected revisitation of the same elif directive");
+}
+
/// Simple lookup for a SourceLocation (specifically one denoting the hash in
/// an inclusion directive) in the map of inclusion information, FileChanges.
const InclusionRewriter::IncludedFile *
@@ -233,6 +254,13 @@ InclusionRewriter::FindEnteredModule(SourceLocation Loc) const {
return nullptr;
}
+bool InclusionRewriter::IsIfAtLocationTrue(SourceLocation Loc) const {
+ const auto I = IfConditions.find(Loc.getRawEncoding());
+ if (I != IfConditions.end())
+ return I->second;
+ return false;
+}
+
/// Detect the likely line ending style of \p FromFile by examining the first
/// newline found within it.
static StringRef DetectEOL(const MemoryBuffer &FromFile) {
@@ -346,80 +374,6 @@ StringRef InclusionRewriter::NextIdentifierName(Lexer &RawLex,
return StringRef();
}
-// Expand __has_include and __has_include_next if possible. If there's no
-// definitive answer return false.
-bool InclusionRewriter::HandleHasInclude(
- FileID FileId, Lexer &RawLex, const DirectoryLookup *Lookup, Token &Tok,
- bool &FileExists) {
- // Lex the opening paren.
- RawLex.LexFromRawLexer(Tok);
- if (Tok.isNot(tok::l_paren))
- return false;
-
- RawLex.LexFromRawLexer(Tok);
-
- SmallString<128> FilenameBuffer;
- StringRef Filename;
- // Since the raw lexer doesn't give us angle_literals we have to parse them
- // ourselves.
- // FIXME: What to do if the file name is a macro?
- if (Tok.is(tok::less)) {
- RawLex.LexFromRawLexer(Tok);
-
- FilenameBuffer += '<';
- do {
- if (Tok.is(tok::eod)) // Sanity check.
- return false;
-
- if (Tok.is(tok::raw_identifier))
- PP.LookUpIdentifierInfo(Tok);
-
- // Get the string piece.
- SmallVector<char, 128> TmpBuffer;
- bool Invalid = false;
- StringRef TmpName = PP.getSpelling(Tok, TmpBuffer, &Invalid);
- if (Invalid)
- return false;
-
- FilenameBuffer += TmpName;
-
- RawLex.LexFromRawLexer(Tok);
- } while (Tok.isNot(tok::greater));
-
- FilenameBuffer += '>';
- Filename = FilenameBuffer;
- } else {
- if (Tok.isNot(tok::string_literal))
- return false;
-
- bool Invalid = false;
- Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid);
- if (Invalid)
- return false;
- }
-
- // Lex the closing paren.
- RawLex.LexFromRawLexer(Tok);
- if (Tok.isNot(tok::r_paren))
- return false;
-
- // Now ask HeaderInfo if it knows about the header.
- // FIXME: Subframeworks aren't handled here. Do we care?
- bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename);
- const DirectoryLookup *CurDir;
- const FileEntry *FileEnt = PP.getSourceManager().getFileEntryForID(FileId);
- SmallVector<std::pair<const FileEntry *, const DirectoryEntry *>, 1>
- Includers;
- Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir()));
- // FIXME: Why don't we call PP.LookupFile here?
- const FileEntry *File = PP.getHeaderSearchInfo().LookupFile(
- Filename, SourceLocation(), isAngled, Lookup, CurDir, Includers, nullptr,
- nullptr, nullptr, nullptr, nullptr, nullptr);
-
- FileExists = File != nullptr;
- return true;
-}
-
/// Use a raw lexer to analyze \p FileId, incrementally copying parts of it
/// and including content of included files recursively.
void InclusionRewriter::Process(FileID FileId,
@@ -519,53 +473,33 @@ void InclusionRewriter::Process(FileID FileId,
case tok::pp_elif: {
bool elif = (RawToken.getIdentifierInfo()->getPPKeywordID() ==
tok::pp_elif);
- // Rewrite special builtin macros to avoid pulling in host details.
+ bool isTrue = IsIfAtLocationTrue(RawToken.getLocation());
+ OutputContentUpTo(FromFile, NextToWrite,
+ SM.getFileOffset(HashToken.getLocation()),
+ LocalEOL, Line, /*EnsureNewline=*/true);
do {
- // Walk over the directive.
RawLex.LexFromRawLexer(RawToken);
- if (RawToken.is(tok::raw_identifier))
- PP.LookUpIdentifierInfo(RawToken);
-
- if (RawToken.is(tok::identifier)) {
- bool HasFile;
- SourceLocation Loc = RawToken.getLocation();
-
- // Rewrite __has_include(x)
- if (RawToken.getIdentifierInfo()->isStr("__has_include")) {
- if (!HandleHasInclude(FileId, RawLex, nullptr, RawToken,
- HasFile))
- continue;
- // Rewrite __has_include_next(x)
- } else if (RawToken.getIdentifierInfo()->isStr(
- "__has_include_next")) {
- if (DirLookup)
- ++DirLookup;
-
- if (!HandleHasInclude(FileId, RawLex, DirLookup, RawToken,
- HasFile))
- continue;
- } else {
- continue;
- }
- // Replace the macro with (0) or (1), followed by the commented
- // out macro for reference.
- OutputContentUpTo(FromFile, NextToWrite, SM.getFileOffset(Loc),
- LocalEOL, Line, false);
- OS << '(' << (int) HasFile << ")/*";
- OutputContentUpTo(FromFile, NextToWrite,
- SM.getFileOffset(RawToken.getLocation()) +
- RawToken.getLength(),
- LocalEOL, Line, false);
- OS << "*/";
- }
- } while (RawToken.isNot(tok::eod));
+ } while (!RawToken.is(tok::eod) && RawToken.isNot(tok::eof));
+ // We need to disable the old condition, but that is tricky.
+ // Trying to comment it out can easily lead to comment nesting.
+ // So instead make the condition harmless by making it enclose
+ // and empty block. Moreover, put it itself inside an #if 0 block
+ // to disable it from getting evaluated (e.g. __has_include_next
+ // warns if used from the primary source file).
+ OS << "#if 0 /* disabled by -frewrite-includes */" << MainEOL;
if (elif) {
- OutputContentUpTo(FromFile, NextToWrite,
- SM.getFileOffset(RawToken.getLocation()) +
- RawToken.getLength(),
- LocalEOL, Line, /*EnsureNewline=*/ true);
- WriteLineInfo(FileName, Line, FileType);
+ OS << "#if 0" << MainEOL;
}
+ OutputContentUpTo(FromFile, NextToWrite,
+ SM.getFileOffset(RawToken.getLocation()) +
+ RawToken.getLength(),
+ LocalEOL, Line, /*EnsureNewline=*/true);
+ // Close the empty block and the disabling block.
+ OS << "#endif" << MainEOL;
+ OS << "#endif /* disabled by -frewrite-includes */" << MainEOL;
+ OS << (elif ? "#elif " : "#if ") << (isTrue ? "1" : "0")
+ << " /* evaluated by -frewrite-includes */" << MainEOL;
+ WriteLineInfo(FileName, Line, FileType);
break;
}
case tok::pp_endif:
diff --git a/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index bd091ee03351..45495065ada6 100644
--- a/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -505,7 +505,7 @@ namespace {
/// otherwise.
bool convertBlockPointerToFunctionPointer(QualType &T) {
if (isTopLevelBlockPointerType(T)) {
- const BlockPointerType *BPT = T->getAs<BlockPointerType>();
+ const auto *BPT = T->castAs<BlockPointerType>();
T = Context->getPointerType(BPT->getPointeeType());
return true;
}
@@ -597,8 +597,8 @@ namespace {
StringLiteral *getStringLiteral(StringRef Str) {
QualType StrType = Context->getConstantArrayType(
- Context->CharTy, llvm::APInt(32, Str.size() + 1), ArrayType::Normal,
- 0);
+ Context->CharTy, llvm::APInt(32, Str.size() + 1), nullptr,
+ ArrayType::Normal, 0);
return StringLiteral::Create(*Context, Str, StringLiteral::Ascii,
/*Pascal=*/false, StrType, SourceLocation());
}
@@ -663,7 +663,7 @@ std::unique_ptr<ASTConsumer> clang::CreateModernObjCRewriter(
const std::string &InFile, std::unique_ptr<raw_ostream> OS,
DiagnosticsEngine &Diags, const LangOptions &LOpts,
bool SilenceRewriteMacroWarning, bool LineInfo) {
- return llvm::make_unique<RewriteModernObjC>(InFile, std::move(OS), Diags,
+ return std::make_unique<RewriteModernObjC>(InFile, std::move(OS), Diags,
LOpts, SilenceRewriteMacroWarning,
LineInfo);
}
@@ -852,12 +852,11 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) {
IvarT = GetGroupRecordTypeForObjCIvarBitfield(D);
if (!isa<TypedefType>(IvarT) && IvarT->isRecordType()) {
- RecordDecl *RD = IvarT->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = IvarT->castAs<RecordType>()->getDecl();
RD = RD->getDefinition();
if (RD && !RD->getDeclName().getAsIdentifierInfo()) {
// decltype(((Foo_IMPL*)0)->bar) *
- ObjCContainerDecl *CDecl =
- dyn_cast<ObjCContainerDecl>(D->getDeclContext());
+ auto *CDecl = cast<ObjCContainerDecl>(D->getDeclContext());
// ivar in class extensions requires special treatment.
if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
CDecl = CatDecl->getClassInterface();
@@ -1332,6 +1331,7 @@ void RewriteModernObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) {
ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID);
ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID);
+ assert((IMD || CID) && "Unknown implementation type");
if (IMD) {
if (IMD->getIvarRBraceLoc().isValid()) {
@@ -2103,8 +2103,7 @@ RewriteModernObjC::SynthesizeCallToFunctionDecl(FunctionDecl *FD,
ImplicitCastExpr::Create(*Context, pToFunc, CK_FunctionToPointerDecay,
DRE, nullptr, VK_RValue);
- const FunctionType *FT = msgSendType->getAs<FunctionType>();
-
+ const auto *FT = msgSendType->castAs<FunctionType>();
CallExpr *Exp = CallExpr::Create(
*Context, ICE, Args, FT->getCallResultType(*Context), VK_RValue, EndLoc);
return Exp;
@@ -2752,7 +2751,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
// Create a call to objc_getClass("NSArray"). It will be th 1st argument.
ObjCInterfaceDecl *Class =
- expType->getPointeeType()->getAs<ObjCObjectType>()->getInterface();
+ expType->getPointeeType()->castAs<ObjCObjectType>()->getInterface();
IdentifierInfo *clsName = Class->getIdentifier();
ClsExprs.push_back(getStringLiteral(clsName->getName()));
@@ -2806,7 +2805,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
- const FunctionType *FT = msgSendType->getAs<FunctionType>();
+ const FunctionType *FT = msgSendType->castAs<FunctionType>();
CallExpr *CE = CallExpr::Create(*Context, PE, MsgExprs, FT->getReturnType(),
VK_RValue, EndLoc);
ReplaceStmt(Exp, CE);
@@ -2894,7 +2893,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
// Create a call to objc_getClass("NSArray"). It will be th 1st argument.
ObjCInterfaceDecl *Class =
- expType->getPointeeType()->getAs<ObjCObjectType>()->getInterface();
+ expType->getPointeeType()->castAs<ObjCObjectType>()->getInterface();
IdentifierInfo *clsName = Class->getIdentifier();
ClsExprs.push_back(getStringLiteral(clsName->getName()));
@@ -2957,7 +2956,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
- const FunctionType *FT = msgSendType->getAs<FunctionType>();
+ const FunctionType *FT = msgSendType->castAs<FunctionType>();
CallExpr *CE = CallExpr::Create(*Context, PE, MsgExprs, FT->getReturnType(),
VK_RValue, EndLoc);
ReplaceStmt(Exp, CE);
@@ -3309,7 +3308,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
case ObjCMessageExpr::Class: {
SmallVector<Expr*, 8> ClsExprs;
ObjCInterfaceDecl *Class
- = Exp->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
+ = Exp->getClassReceiver()->castAs<ObjCObjectType>()->getInterface();
IdentifierInfo *clsName = Class->getIdentifier();
ClsExprs.push_back(getStringLiteral(clsName->getName()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, ClsExprs,
@@ -3530,7 +3529,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
- const FunctionType *FT = msgSendType->getAs<FunctionType>();
+ const FunctionType *FT = msgSendType->castAs<FunctionType>();
CallExpr *CE = CallExpr::Create(*Context, PE, MsgExprs, FT->getReturnType(),
VK_RValue, EndLoc);
Stmt *ReplacingStmt = CE;
@@ -3637,7 +3636,7 @@ bool RewriteModernObjC::RewriteObjCFieldDeclType(QualType &Type,
return RewriteObjCFieldDeclType(ElemTy, Result);
}
else if (Type->isRecordType()) {
- RecordDecl *RD = Type->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
if (RD->isCompleteDefinition()) {
if (RD->isStruct())
Result += "\n\tstruct ";
@@ -3660,7 +3659,7 @@ bool RewriteModernObjC::RewriteObjCFieldDeclType(QualType &Type,
}
}
else if (Type->isEnumeralType()) {
- EnumDecl *ED = Type->getAs<EnumType>()->getDecl();
+ EnumDecl *ED = Type->castAs<EnumType>()->getDecl();
if (ED->isCompleteDefinition()) {
Result += "\n\tenum ";
Result += ED->getName();
@@ -3727,15 +3726,15 @@ void RewriteModernObjC::RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDec
return;
if (Type->isArrayType())
Type = Context->getBaseElementType(Type);
- ObjCContainerDecl *IDecl =
- dyn_cast<ObjCContainerDecl>(fieldDecl->getDeclContext());
+
+ auto *IDecl = dyn_cast<ObjCContainerDecl>(fieldDecl->getDeclContext());
TagDecl *TD = nullptr;
if (Type->isRecordType()) {
- TD = Type->getAs<RecordType>()->getDecl();
+ TD = Type->castAs<RecordType>()->getDecl();
}
else if (Type->isEnumeralType()) {
- TD = Type->getAs<EnumType>()->getDecl();
+ TD = Type->castAs<EnumType>()->getDecl();
}
if (TD) {
@@ -5753,7 +5752,7 @@ void RewriteModernObjC::HandleDeclInMainFile(Decl *D) {
}
}
} else if (VD->getType()->isRecordType()) {
- RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = VD->getType()->castAs<RecordType>()->getDecl();
if (RD->isCompleteDefinition())
RewriteRecordBody(RD);
}
@@ -7494,7 +7493,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
IvarT = GetGroupRecordTypeForObjCIvarBitfield(D);
if (!isa<TypedefType>(IvarT) && IvarT->isRecordType()) {
- RecordDecl *RD = IvarT->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = IvarT->castAs<RecordType>()->getDecl();
RD = RD->getDefinition();
if (RD && !RD->getDeclName().getAsIdentifierInfo()) {
// decltype(((Foo_IMPL*)0)->bar) *
diff --git a/lib/Frontend/Rewrite/RewriteObjC.cpp b/lib/Frontend/Rewrite/RewriteObjC.cpp
index 05078baee790..6a22da178fbc 100644
--- a/lib/Frontend/Rewrite/RewriteObjC.cpp
+++ b/lib/Frontend/Rewrite/RewriteObjC.cpp
@@ -416,7 +416,7 @@ namespace {
/// otherwise.
bool convertBlockPointerToFunctionPointer(QualType &T) {
if (isTopLevelBlockPointerType(T)) {
- const BlockPointerType *BPT = T->getAs<BlockPointerType>();
+ const auto *BPT = T->castAs<BlockPointerType>();
T = Context->getPointerType(BPT->getPointeeType());
return true;
}
@@ -497,8 +497,8 @@ namespace {
StringLiteral *getStringLiteral(StringRef Str) {
QualType StrType = Context->getConstantArrayType(
- Context->CharTy, llvm::APInt(32, Str.size() + 1), ArrayType::Normal,
- 0);
+ Context->CharTy, llvm::APInt(32, Str.size() + 1), nullptr,
+ ArrayType::Normal, 0);
return StringLiteral::Create(*Context, Str, StringLiteral::Ascii,
/*Pascal=*/false, StrType, SourceLocation());
}
@@ -593,7 +593,7 @@ clang::CreateObjCRewriter(const std::string &InFile,
std::unique_ptr<raw_ostream> OS,
DiagnosticsEngine &Diags, const LangOptions &LOpts,
bool SilenceRewriteMacroWarning) {
- return llvm::make_unique<RewriteObjCFragileABI>(
+ return std::make_unique<RewriteObjCFragileABI>(
InFile, std::move(OS), Diags, LOpts, SilenceRewriteMacroWarning);
}
@@ -1163,6 +1163,7 @@ void RewriteObjC::RewriteObjCMethodDecl(const ObjCInterfaceDecl *IDecl,
void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(OID);
ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(OID);
+ assert((IMD || CID) && "Unknown ImplementationDecl");
InsertText(IMD ? IMD->getBeginLoc() : CID->getBeginLoc(), "// ");
@@ -2017,7 +2018,7 @@ RewriteObjC::SynthesizeCallToFunctionDecl(FunctionDecl *FD,
ImplicitCastExpr::Create(*Context, pToFunc, CK_FunctionToPointerDecay,
DRE, nullptr, VK_RValue);
- const FunctionType *FT = msgSendType->getAs<FunctionType>();
+ const auto *FT = msgSendType->castAs<FunctionType>();
CallExpr *Exp = CallExpr::Create(
*Context, ICE, Args, FT->getCallResultType(*Context), VK_RValue, EndLoc);
@@ -2285,7 +2286,7 @@ void RewriteObjC::RewriteBlockPointerTypeVariable(std::string& Str,
void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) {
SourceLocation FunLocStart = FD->getTypeSpecStartLoc();
const FunctionType *funcType = FD->getType()->getAs<FunctionType>();
- const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(funcType);
+ const FunctionProtoType *proto = dyn_cast_or_null<FunctionProtoType>(funcType);
if (!proto)
return;
QualType Type = proto->getReturnType();
@@ -2604,7 +2605,7 @@ CallExpr *RewriteObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavo
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast);
- const FunctionType *FT = msgSendType->getAs<FunctionType>();
+ const auto *FT = msgSendType->castAs<FunctionType>();
CallExpr *STCE = CallExpr::Create(*Context, PE, MsgExprs, FT->getReturnType(),
VK_RValue, SourceLocation());
return STCE;
@@ -2735,8 +2736,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
case ObjCMessageExpr::Class: {
SmallVector<Expr*, 8> ClsExprs;
- ObjCInterfaceDecl *Class
- = Exp->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
+ auto *Class =
+ Exp->getClassReceiver()->castAs<ObjCObjectType>()->getInterface();
IdentifierInfo *clsName = Class->getIdentifier();
ClsExprs.push_back(getStringLiteral(clsName->getName()));
CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, ClsExprs,
@@ -2957,7 +2958,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast);
- const FunctionType *FT = msgSendType->getAs<FunctionType>();
+ const auto *FT = msgSendType->castAs<FunctionType>();
CallExpr *CE = CallExpr::Create(*Context, PE, MsgExprs, FT->getReturnType(),
VK_RValue, EndLoc);
Stmt *ReplacingStmt = CE;
@@ -4849,7 +4850,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
}
}
} else if (VD->getType()->isRecordType()) {
- RecordDecl *RD = VD->getType()->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = VD->getType()->castAs<RecordType>()->getDecl();
if (RD->isCompleteDefinition())
RewriteRecordBody(RD);
}
diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp
index c1434a95cc70..8042b52ddc03 100644
--- a/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -296,7 +296,7 @@ namespace clang {
namespace serialized_diags {
std::unique_ptr<DiagnosticConsumer>
create(StringRef OutputFile, DiagnosticOptions *Diags, bool MergeChildRecords) {
- return llvm::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords);
+ return std::make_unique<SDiagsWriter>(OutputFile, Diags, MergeChildRecords);
}
} // end namespace serialized_diags
@@ -743,7 +743,7 @@ DiagnosticsEngine *SDiagsWriter::getMetaDiags() {
IntrusiveRefCntPtr<DiagnosticIDs> IDs(new DiagnosticIDs());
auto Client =
new TextDiagnosticPrinter(llvm::errs(), State->DiagOpts.get());
- State->MetaDiagnostics = llvm::make_unique<DiagnosticsEngine>(
+ State->MetaDiagnostics = std::make_unique<DiagnosticsEngine>(
IDs, State->DiagOpts.get(), Client);
}
return State->MetaDiagnostics.get();
@@ -780,8 +780,8 @@ void SDiagsWriter::finish() {
}
std::error_code EC;
- auto OS = llvm::make_unique<llvm::raw_fd_ostream>(State->OutputFile.c_str(),
- EC, llvm::sys::fs::F_None);
+ auto OS = std::make_unique<llvm::raw_fd_ostream>(State->OutputFile.c_str(),
+ EC, llvm::sys::fs::OF_None);
if (EC) {
getMetaDiags()->Report(diag::warn_fe_serialized_diag_failure)
<< State->OutputFile << EC.message();
diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp
index d0c91286250e..7bb6c5b74d5f 100644
--- a/lib/Frontend/TextDiagnostic.cpp
+++ b/lib/Frontend/TextDiagnostic.cpp
@@ -683,8 +683,9 @@ void TextDiagnostic::emitDiagnosticMessage(
if (DiagOpts->ShowColors)
OS.resetColor();
- printDiagnosticLevel(OS, Level, DiagOpts->ShowColors,
- DiagOpts->CLFallbackMode);
+ if (DiagOpts->ShowLevel)
+ printDiagnosticLevel(OS, Level, DiagOpts->ShowColors,
+ DiagOpts->CLFallbackMode);
printDiagnosticMessage(OS,
/*IsSupplemental*/ Level == DiagnosticsEngine::Note,
Message, OS.tell() - StartOfLocationInfo,
@@ -762,7 +763,7 @@ void TextDiagnostic::printDiagnosticMessage(raw_ostream &OS,
void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) {
SmallVector<char, 128> AbsoluteFilename;
if (DiagOpts->AbsolutePath) {
- const DirectoryEntry *Dir = SM.getFileManager().getDirectory(
+ auto Dir = SM.getFileManager().getDirectory(
llvm::sys::path::parent_path(Filename));
if (Dir) {
// We want to print a simplified absolute path, i. e. without "dots".
@@ -780,12 +781,12 @@ void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) {
// on Windows we can just use llvm::sys::path::remove_dots(), because,
// on that system, both aforementioned paths point to the same place.
#ifdef _WIN32
- SmallString<4096> DirName = Dir->getName();
+ SmallString<4096> DirName = (*Dir)->getName();
llvm::sys::fs::make_absolute(DirName);
llvm::sys::path::native(DirName);
llvm::sys::path::remove_dots(DirName, /* remove_dot_dot */ true);
#else
- StringRef DirName = SM.getFileManager().getCanonicalName(Dir);
+ StringRef DirName = SM.getFileManager().getCanonicalName(*Dir);
#endif
llvm::sys::path::append(AbsoluteFilename, DirName,
llvm::sys::path::filename(Filename));
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index a68ef03d4db1..82c2af87706e 100644
--- a/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -528,15 +528,16 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
// Lookup file via Preprocessor, like a #include.
const DirectoryLookup *CurDir;
- const FileEntry *FE =
+ Optional<FileEntryRef> File =
PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir,
nullptr, nullptr, nullptr, nullptr, nullptr);
- if (!FE) {
+ if (!File) {
Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
diag::err_verify_missing_file) << Filename << KindStr;
continue;
}
+ const FileEntry *FE = &File->getFileEntry();
if (SM.translateFile(FE).isInvalid())
SM.createFileID(FE, Pos, SrcMgr::C_User);
@@ -671,7 +672,7 @@ void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
#ifndef NDEBUG
// Debug build tracks parsed files.
const_cast<Preprocessor *>(PP)->addPPCallbacks(
- llvm::make_unique<VerifyFileTracker>(*this, *SrcManager));
+ std::make_unique<VerifyFileTracker>(*this, *SrcManager));
#endif
}
}
@@ -1116,7 +1117,7 @@ std::unique_ptr<Directive> Directive::create(bool RegexKind,
bool MatchAnyLine, StringRef Text,
unsigned Min, unsigned Max) {
if (!RegexKind)
- return llvm::make_unique<StandardDirective>(DirectiveLoc, DiagnosticLoc,
+ return std::make_unique<StandardDirective>(DirectiveLoc, DiagnosticLoc,
MatchAnyLine, Text, Min, Max);
// Parse the directive into a regular expression.
@@ -1142,6 +1143,6 @@ std::unique_ptr<Directive> Directive::create(bool RegexKind,
}
}
- return llvm::make_unique<RegexDirective>(
+ return std::make_unique<RegexDirective>(
DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max, RegexStr);
}
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 69e773658c5c..9bf70b793d9b 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -41,38 +41,36 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
(void)Action;
switch (CI.getFrontendOpts().ProgramAction) {
- case ASTDeclList: return llvm::make_unique<ASTDeclListAction>();
- case ASTDump: return llvm::make_unique<ASTDumpAction>();
- case ASTPrint: return llvm::make_unique<ASTPrintAction>();
- case ASTView: return llvm::make_unique<ASTViewAction>();
+ case ASTDeclList: return std::make_unique<ASTDeclListAction>();
+ case ASTDump: return std::make_unique<ASTDumpAction>();
+ case ASTPrint: return std::make_unique<ASTPrintAction>();
+ case ASTView: return std::make_unique<ASTViewAction>();
case DumpCompilerOptions:
- return llvm::make_unique<DumpCompilerOptionsAction>();
- case DumpRawTokens: return llvm::make_unique<DumpRawTokensAction>();
- case DumpTokens: return llvm::make_unique<DumpTokensAction>();
- case EmitAssembly: return llvm::make_unique<EmitAssemblyAction>();
- case EmitBC: return llvm::make_unique<EmitBCAction>();
- case EmitHTML: return llvm::make_unique<HTMLPrintAction>();
- case EmitLLVM: return llvm::make_unique<EmitLLVMAction>();
- case EmitLLVMOnly: return llvm::make_unique<EmitLLVMOnlyAction>();
- case EmitCodeGenOnly: return llvm::make_unique<EmitCodeGenOnlyAction>();
- case EmitObj: return llvm::make_unique<EmitObjAction>();
- case FixIt: return llvm::make_unique<FixItAction>();
+ return std::make_unique<DumpCompilerOptionsAction>();
+ case DumpRawTokens: return std::make_unique<DumpRawTokensAction>();
+ case DumpTokens: return std::make_unique<DumpTokensAction>();
+ case EmitAssembly: return std::make_unique<EmitAssemblyAction>();
+ case EmitBC: return std::make_unique<EmitBCAction>();
+ case EmitHTML: return std::make_unique<HTMLPrintAction>();
+ case EmitLLVM: return std::make_unique<EmitLLVMAction>();
+ case EmitLLVMOnly: return std::make_unique<EmitLLVMOnlyAction>();
+ case EmitCodeGenOnly: return std::make_unique<EmitCodeGenOnlyAction>();
+ case EmitObj: return std::make_unique<EmitObjAction>();
+ case FixIt: return std::make_unique<FixItAction>();
case GenerateModule:
- return llvm::make_unique<GenerateModuleFromModuleMapAction>();
+ return std::make_unique<GenerateModuleFromModuleMapAction>();
case GenerateModuleInterface:
- return llvm::make_unique<GenerateModuleInterfaceAction>();
+ return std::make_unique<GenerateModuleInterfaceAction>();
case GenerateHeaderModule:
- return llvm::make_unique<GenerateHeaderModuleAction>();
- case GeneratePCH: return llvm::make_unique<GeneratePCHAction>();
- case GenerateInterfaceYAMLExpV1:
- return llvm::make_unique<GenerateInterfaceYAMLExpV1Action>();
- case GenerateInterfaceTBEExpV1:
- return llvm::make_unique<GenerateInterfaceTBEExpV1Action>();
- case InitOnly: return llvm::make_unique<InitOnlyAction>();
- case ParseSyntaxOnly: return llvm::make_unique<SyntaxOnlyAction>();
- case ModuleFileInfo: return llvm::make_unique<DumpModuleInfoAction>();
- case VerifyPCH: return llvm::make_unique<VerifyPCHAction>();
- case TemplightDump: return llvm::make_unique<TemplightDumpAction>();
+ return std::make_unique<GenerateHeaderModuleAction>();
+ case GeneratePCH: return std::make_unique<GeneratePCHAction>();
+ case GenerateInterfaceIfsExpV1:
+ return std::make_unique<GenerateInterfaceIfsExpV1Action>();
+ case InitOnly: return std::make_unique<InitOnlyAction>();
+ case ParseSyntaxOnly: return std::make_unique<SyntaxOnlyAction>();
+ case ModuleFileInfo: return std::make_unique<DumpModuleInfoAction>();
+ case VerifyPCH: return std::make_unique<VerifyPCHAction>();
+ case TemplightDump: return std::make_unique<TemplightDumpAction>();
case PluginAction: {
for (FrontendPluginRegistry::iterator it =
@@ -93,35 +91,35 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
return nullptr;
}
- case PrintPreamble: return llvm::make_unique<PrintPreambleAction>();
+ case PrintPreamble: return std::make_unique<PrintPreambleAction>();
case PrintPreprocessedInput: {
if (CI.getPreprocessorOutputOpts().RewriteIncludes ||
CI.getPreprocessorOutputOpts().RewriteImports)
- return llvm::make_unique<RewriteIncludesAction>();
- return llvm::make_unique<PrintPreprocessedAction>();
+ return std::make_unique<RewriteIncludesAction>();
+ return std::make_unique<PrintPreprocessedAction>();
}
- case RewriteMacros: return llvm::make_unique<RewriteMacrosAction>();
- case RewriteTest: return llvm::make_unique<RewriteTestAction>();
+ case RewriteMacros: return std::make_unique<RewriteMacrosAction>();
+ case RewriteTest: return std::make_unique<RewriteTestAction>();
#if CLANG_ENABLE_OBJC_REWRITER
- case RewriteObjC: return llvm::make_unique<RewriteObjCAction>();
+ case RewriteObjC: return std::make_unique<RewriteObjCAction>();
#else
case RewriteObjC: Action = "RewriteObjC"; break;
#endif
#if CLANG_ENABLE_ARCMT
case MigrateSource:
- return llvm::make_unique<arcmt::MigrateSourceAction>();
+ return std::make_unique<arcmt::MigrateSourceAction>();
#else
case MigrateSource: Action = "MigrateSource"; break;
#endif
#if CLANG_ENABLE_STATIC_ANALYZER
- case RunAnalysis: return llvm::make_unique<ento::AnalysisAction>();
+ case RunAnalysis: return std::make_unique<ento::AnalysisAction>();
#else
case RunAnalysis: Action = "RunAnalysis"; break;
#endif
- case RunPreprocessorOnly: return llvm::make_unique<PreprocessOnlyAction>();
+ case RunPreprocessorOnly: return std::make_unique<PreprocessOnlyAction>();
case PrintDependencyDirectivesSourceMinimizerOutput:
- return llvm::make_unique<PrintDependencyDirectivesSourceMinimizerAction>();
+ return std::make_unique<PrintDependencyDirectivesSourceMinimizerAction>();
}
#if !CLANG_ENABLE_ARCMT || !CLANG_ENABLE_STATIC_ANALYZER \
@@ -143,7 +141,7 @@ CreateFrontendAction(CompilerInstance &CI) {
const FrontendOptions &FEOpts = CI.getFrontendOpts();
if (FEOpts.FixAndRecompile) {
- Act = llvm::make_unique<FixItRecompile>(std::move(Act));
+ Act = std::make_unique<FixItRecompile>(std::move(Act));
}
#if CLANG_ENABLE_ARCMT
@@ -154,13 +152,13 @@ CreateFrontendAction(CompilerInstance &CI) {
case FrontendOptions::ARCMT_None:
break;
case FrontendOptions::ARCMT_Check:
- Act = llvm::make_unique<arcmt::CheckAction>(std::move(Act));
+ Act = std::make_unique<arcmt::CheckAction>(std::move(Act));
break;
case FrontendOptions::ARCMT_Modify:
- Act = llvm::make_unique<arcmt::ModifyAction>(std::move(Act));
+ Act = std::make_unique<arcmt::ModifyAction>(std::move(Act));
break;
case FrontendOptions::ARCMT_Migrate:
- Act = llvm::make_unique<arcmt::MigrateAction>(std::move(Act),
+ Act = std::make_unique<arcmt::MigrateAction>(std::move(Act),
FEOpts.MTMigrateDir,
FEOpts.ARCMTMigrateReportOut,
FEOpts.ARCMTMigrateEmitARCErrors);
@@ -168,7 +166,7 @@ CreateFrontendAction(CompilerInstance &CI) {
}
if (FEOpts.ObjCMTAction != FrontendOptions::ObjCMT_None) {
- Act = llvm::make_unique<arcmt::ObjCMigrateAction>(std::move(Act),
+ Act = std::make_unique<arcmt::ObjCMigrateAction>(std::move(Act),
FEOpts.MTMigrateDir,
FEOpts.ObjCMTAction);
}
@@ -178,7 +176,7 @@ CreateFrontendAction(CompilerInstance &CI) {
// If there are any AST files to merge, create a frontend action
// adaptor to perform the merge.
if (!FEOpts.ASTMergeFiles.empty())
- Act = llvm::make_unique<ASTMergeAction>(std::move(Act),
+ Act = std::make_unique<ASTMergeAction>(std::move(Act),
FEOpts.ASTMergeFiles);
return Act;
@@ -187,11 +185,11 @@ CreateFrontendAction(CompilerInstance &CI) {
bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
// Honor -help.
if (Clang->getFrontendOpts().ShowHelp) {
- std::unique_ptr<OptTable> Opts = driver::createDriverOptTable();
- Opts->PrintHelp(llvm::outs(), "clang -cc1 [options] file...",
- "LLVM 'Clang' Compiler: http://clang.llvm.org",
- /*Include=*/driver::options::CC1Option,
- /*Exclude=*/0, /*ShowAllAliases=*/false);
+ driver::getDriverOptTable().PrintHelp(
+ llvm::outs(), "clang -cc1 [options] file...",
+ "LLVM 'Clang' Compiler: http://clang.llvm.org",
+ /*Include=*/driver::options::CC1Option,
+ /*Exclude=*/0, /*ShowAllAliases=*/false);
return true;
}
@@ -231,7 +229,7 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
// This should happen AFTER plugins have been loaded!
if (!Clang->getFrontendOpts().LLVMArgs.empty()) {
unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size();
- auto Args = llvm::make_unique<const char*[]>(NumArgs + 2);
+ auto Args = std::make_unique<const char*[]>(NumArgs + 2);
Args[0] = "clang (LLVM option parsing)";
for (unsigned i = 0; i != NumArgs; ++i)
Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str();
@@ -272,6 +270,7 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
AnOpts,
Clang->getDiagnostics(),
Clang->getLangOpts());
+ return true;
}
// Honor -analyzer-config-help.
diff --git a/lib/Headers/__clang_cuda_intrinsics.h b/lib/Headers/__clang_cuda_intrinsics.h
index 2970d17f89ee..b67461a146fc 100644
--- a/lib/Headers/__clang_cuda_intrinsics.h
+++ b/lib/Headers/__clang_cuda_intrinsics.h
@@ -211,7 +211,15 @@ inline __device__ unsigned int __ballot_sync(unsigned int mask, int pred) {
return __nvvm_vote_ballot_sync(mask, pred);
}
-inline __device__ unsigned int __activemask() { return __nvvm_vote_ballot(1); }
+inline __device__ unsigned int __activemask() {
+#if CUDA_VERSION < 9020
+ return __nvvm_vote_ballot(1);
+#else
+ unsigned int mask;
+ asm volatile("activemask.b32 %0;" : "=r"(mask));
+ return mask;
+#endif
+}
inline __device__ unsigned int __fns(unsigned mask, unsigned base, int offset) {
return __nvvm_fns(mask, base, offset);
diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h
index 4008440b2bc5..8352f8f740c2 100644
--- a/lib/Headers/altivec.h
+++ b/lib/Headers/altivec.h
@@ -2761,8 +2761,8 @@ static __inline__ vector double __ATTRS_o_ai vec_xl_len(double *__a,
return (vector double)__builtin_vsx_lxvl(__a, (__b << 56));
}
-static __inline__ vector double __ATTRS_o_ai vec_xl_len_r(unsigned char *__a,
- size_t __b) {
+static __inline__ vector unsigned char __ATTRS_o_ai
+vec_xl_len_r(unsigned char *__a, size_t __b) {
vector unsigned char __res =
(vector unsigned char)__builtin_vsx_lxvll(__a, (__b << 56));
#ifdef __LITTLE_ENDIAN__
@@ -2876,9 +2876,10 @@ static __inline__ vector double __ATTRS_o_ai vec_cpsgn(vector double __a,
#ifdef __VSX__
#define vec_ctf(__a, __b) \
_Generic((__a), vector int \
- : (vector float)__builtin_altivec_vcfsx((__a), (__b)), \
+ : (vector float)__builtin_altivec_vcfsx((vector int)(__a), (__b)), \
vector unsigned int \
- : (vector float)__builtin_altivec_vcfux((vector int)(__a), (__b)), \
+ : (vector float)__builtin_altivec_vcfux((vector unsigned int)(__a), \
+ (__b)), \
vector unsigned long long \
: (__builtin_convertvector((vector unsigned long long)(__a), \
vector double) * \
@@ -2892,9 +2893,10 @@ static __inline__ vector double __ATTRS_o_ai vec_cpsgn(vector double __a,
#else
#define vec_ctf(__a, __b) \
_Generic((__a), vector int \
- : (vector float)__builtin_altivec_vcfsx((__a), (__b)), \
+ : (vector float)__builtin_altivec_vcfsx((vector int)(__a), (__b)), \
vector unsigned int \
- : (vector float)__builtin_altivec_vcfux((vector int)(__a), (__b)))
+ : (vector float)__builtin_altivec_vcfux((vector unsigned int)(__a), \
+ (__b)))
#endif
/* vec_vcfsx */
@@ -2910,10 +2912,11 @@ static __inline__ vector double __ATTRS_o_ai vec_cpsgn(vector double __a,
#ifdef __VSX__
#define vec_cts(__a, __b) \
_Generic((__a), vector float \
- : __builtin_altivec_vctsxs((__a), (__b)), vector double \
+ : __builtin_altivec_vctsxs((vector float)(__a), (__b)), \
+ vector double \
: __extension__({ \
vector double __ret = \
- (__a) * \
+ (vector double)(__a) * \
(vector double)(vector unsigned long long)((0x3ffULL + (__b)) \
<< 52); \
__builtin_convertvector(__ret, vector signed long long); \
@@ -2931,10 +2934,11 @@ static __inline__ vector double __ATTRS_o_ai vec_cpsgn(vector double __a,
#ifdef __VSX__
#define vec_ctu(__a, __b) \
_Generic((__a), vector float \
- : __builtin_altivec_vctuxs((__a), (__b)), vector double \
+ : __builtin_altivec_vctuxs((vector float)(__a), (__b)), \
+ vector double \
: __extension__({ \
vector double __ret = \
- (__a) * \
+ (vector double)(__a) * \
(vector double)(vector unsigned long long)((0x3ffULL + __b) \
<< 52); \
__builtin_convertvector(__ret, vector unsigned long long); \
@@ -3286,9 +3290,7 @@ static __inline__ vector double __ATTRS_o_ai vec_div(vector double __a,
/* vec_dss */
-static __inline__ void __attribute__((__always_inline__)) vec_dss(int __a) {
- __builtin_altivec_dss(__a);
-}
+#define vec_dss __builtin_altivec_dss
/* vec_dssall */
@@ -6301,19 +6303,20 @@ static __inline__ vector float __ATTRS_o_ai vec_or(vector float __a,
#ifdef __VSX__
static __inline__ vector double __ATTRS_o_ai vec_or(vector bool long long __a,
vector double __b) {
- return (vector unsigned long long)__a | (vector unsigned long long)__b;
+ return (vector double)((vector unsigned long long)__a |
+ (vector unsigned long long)__b);
}
static __inline__ vector double __ATTRS_o_ai vec_or(vector double __a,
vector bool long long __b) {
- return (vector unsigned long long)__a | (vector unsigned long long)__b;
+ return (vector double)((vector unsigned long long)__a |
+ (vector unsigned long long)__b);
}
static __inline__ vector double __ATTRS_o_ai vec_or(vector double __a,
vector double __b) {
- vector unsigned long long __res =
- (vector unsigned long long)__a | (vector unsigned long long)__b;
- return (vector double)__res;
+ return (vector double)((vector unsigned long long)__a |
+ (vector unsigned long long)__b);
}
static __inline__ vector signed long long __ATTRS_o_ai
@@ -14781,7 +14784,7 @@ static __inline__ int __ATTRS_o_ai vec_all_ne(vector bool long long __a,
static __inline__ int __ATTRS_o_ai vec_all_ne(vector float __a,
vector float __b) {
#ifdef __VSX__
- return __builtin_vsx_xvcmpeqdp_p(__CR6_EQ, __a, __b);
+ return __builtin_vsx_xvcmpeqdp_p(__CR6_EQ, (vector double)__a, (vector double)__b);
#else
return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, __a, __b);
#endif
@@ -16425,27 +16428,27 @@ vec_xl(signed long long __offset, unsigned __int128 *__ptr) {
#ifdef __LITTLE_ENDIAN__
static __inline__ vector signed char __ATTRS_o_ai
vec_xl_be(signed long long __offset, signed char *__ptr) {
- vector signed char __vec = __builtin_vsx_lxvd2x_be(__offset, __ptr);
+ vector signed char __vec = (vector signed char)__builtin_vsx_lxvd2x_be(__offset, __ptr);
return __builtin_shufflevector(__vec, __vec, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14,
13, 12, 11, 10, 9, 8);
}
static __inline__ vector unsigned char __ATTRS_o_ai
vec_xl_be(signed long long __offset, unsigned char *__ptr) {
- vector unsigned char __vec = __builtin_vsx_lxvd2x_be(__offset, __ptr);
+ vector unsigned char __vec = (vector unsigned char)__builtin_vsx_lxvd2x_be(__offset, __ptr);
return __builtin_shufflevector(__vec, __vec, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14,
13, 12, 11, 10, 9, 8);
}
static __inline__ vector signed short __ATTRS_o_ai
vec_xl_be(signed long long __offset, signed short *__ptr) {
- vector signed short __vec = __builtin_vsx_lxvd2x_be(__offset, __ptr);
+ vector signed short __vec = (vector signed short)__builtin_vsx_lxvd2x_be(__offset, __ptr);
return __builtin_shufflevector(__vec, __vec, 3, 2, 1, 0, 7, 6, 5, 4);
}
static __inline__ vector unsigned short __ATTRS_o_ai
vec_xl_be(signed long long __offset, unsigned short *__ptr) {
- vector unsigned short __vec = __builtin_vsx_lxvd2x_be(__offset, __ptr);
+ vector unsigned short __vec = (vector unsigned short)__builtin_vsx_lxvd2x_be(__offset, __ptr);
return __builtin_shufflevector(__vec, __vec, 3, 2, 1, 0, 7, 6, 5, 4);
}
@@ -16583,7 +16586,8 @@ static __inline__ void __ATTRS_o_ai vec_xst_be(vector signed char __vec,
vector signed char __tmp =
__builtin_shufflevector(__vec, __vec, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14,
13, 12, 11, 10, 9, 8);
- __builtin_vsx_stxvd2x_be(__tmp, __offset, __ptr);
+ typedef __attribute__((vector_size(sizeof(__tmp)))) double __vector_double;
+ __builtin_vsx_stxvd2x_be((__vector_double)__tmp, __offset, __ptr);
}
static __inline__ void __ATTRS_o_ai vec_xst_be(vector unsigned char __vec,
@@ -16592,7 +16596,8 @@ static __inline__ void __ATTRS_o_ai vec_xst_be(vector unsigned char __vec,
vector unsigned char __tmp =
__builtin_shufflevector(__vec, __vec, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14,
13, 12, 11, 10, 9, 8);
- __builtin_vsx_stxvd2x_be(__tmp, __offset, __ptr);
+ typedef __attribute__((vector_size(sizeof(__tmp)))) double __vector_double;
+ __builtin_vsx_stxvd2x_be((__vector_double)__tmp, __offset, __ptr);
}
static __inline__ void __ATTRS_o_ai vec_xst_be(vector signed short __vec,
@@ -16600,7 +16605,8 @@ static __inline__ void __ATTRS_o_ai vec_xst_be(vector signed short __vec,
signed short *__ptr) {
vector signed short __tmp =
__builtin_shufflevector(__vec, __vec, 3, 2, 1, 0, 7, 6, 5, 4);
- __builtin_vsx_stxvd2x_be(__tmp, __offset, __ptr);
+ typedef __attribute__((vector_size(sizeof(__tmp)))) double __vector_double;
+ __builtin_vsx_stxvd2x_be((__vector_double)__tmp, __offset, __ptr);
}
static __inline__ void __ATTRS_o_ai vec_xst_be(vector unsigned short __vec,
@@ -16608,7 +16614,8 @@ static __inline__ void __ATTRS_o_ai vec_xst_be(vector unsigned short __vec,
unsigned short *__ptr) {
vector unsigned short __tmp =
__builtin_shufflevector(__vec, __vec, 3, 2, 1, 0, 7, 6, 5, 4);
- __builtin_vsx_stxvd2x_be(__tmp, __offset, __ptr);
+ typedef __attribute__((vector_size(sizeof(__tmp)))) double __vector_double;
+ __builtin_vsx_stxvd2x_be((__vector_double)__tmp, __offset, __ptr);
}
static __inline__ void __ATTRS_o_ai vec_xst_be(vector signed int __vec,
@@ -16620,32 +16627,32 @@ static __inline__ void __ATTRS_o_ai vec_xst_be(vector signed int __vec,
static __inline__ void __ATTRS_o_ai vec_xst_be(vector unsigned int __vec,
signed long long __offset,
unsigned int *__ptr) {
- __builtin_vsx_stxvw4x_be(__vec, __offset, __ptr);
+ __builtin_vsx_stxvw4x_be((vector int)__vec, __offset, __ptr);
}
static __inline__ void __ATTRS_o_ai vec_xst_be(vector float __vec,
signed long long __offset,
float *__ptr) {
- __builtin_vsx_stxvw4x_be(__vec, __offset, __ptr);
+ __builtin_vsx_stxvw4x_be((vector int)__vec, __offset, __ptr);
}
#ifdef __VSX__
static __inline__ void __ATTRS_o_ai vec_xst_be(vector signed long long __vec,
signed long long __offset,
signed long long *__ptr) {
- __builtin_vsx_stxvd2x_be(__vec, __offset, __ptr);
+ __builtin_vsx_stxvd2x_be((vector double)__vec, __offset, __ptr);
}
static __inline__ void __ATTRS_o_ai vec_xst_be(vector unsigned long long __vec,
signed long long __offset,
unsigned long long *__ptr) {
- __builtin_vsx_stxvd2x_be(__vec, __offset, __ptr);
+ __builtin_vsx_stxvd2x_be((vector double)__vec, __offset, __ptr);
}
static __inline__ void __ATTRS_o_ai vec_xst_be(vector double __vec,
signed long long __offset,
double *__ptr) {
- __builtin_vsx_stxvd2x_be(__vec, __offset, __ptr);
+ __builtin_vsx_stxvd2x_be((vector double)__vec, __offset, __ptr);
}
#endif
@@ -16667,13 +16674,13 @@ static __inline__ void __ATTRS_o_ai vec_xst_be(vector unsigned __int128 __vec,
#endif
#ifdef __POWER9_VECTOR__
-#define vec_test_data_class(__a, __b) \
- _Generic((__a), \
- vector float: \
- (vector bool int)__builtin_vsx_xvtstdcsp((__a), (__b)), \
- vector double: \
- (vector bool long long)__builtin_vsx_xvtstdcdp((__a), (__b)) \
- )
+#define vec_test_data_class(__a, __b) \
+ _Generic( \
+ (__a), vector float \
+ : (vector bool int)__builtin_vsx_xvtstdcsp((vector float)(__a), (__b)), \
+ vector double \
+ : (vector bool long long)__builtin_vsx_xvtstdcdp((vector double)(__a), \
+ (__b)))
#endif /* #ifdef __POWER9_VECTOR__ */
diff --git a/lib/Headers/arm_acle.h b/lib/Headers/arm_acle.h
index 096cc261af2c..0510e6fd809f 100644
--- a/lib/Headers/arm_acle.h
+++ b/lib/Headers/arm_acle.h
@@ -613,7 +613,7 @@ __jcvt(double __a) {
#define __arm_wsr64(sysreg, v) __builtin_arm_wsr64(sysreg, v)
#define __arm_wsrp(sysreg, v) __builtin_arm_wsrp(sysreg, v)
-// Memory Tagging Extensions (MTE) Intrinsics
+/* Memory Tagging Extensions (MTE) Intrinsics */
#if __ARM_FEATURE_MEMORY_TAGGING
#define __arm_mte_create_random_tag(__ptr, __mask) __builtin_arm_irg(__ptr, __mask)
#define __arm_mte_increment_tag(__ptr, __tag_offset) __builtin_arm_addg(__ptr, __tag_offset)
@@ -623,6 +623,28 @@ __jcvt(double __a) {
#define __arm_mte_ptrdiff(__ptra, __ptrb) __builtin_arm_subp(__ptra, __ptrb)
#endif
+/* Transactional Memory Extension (TME) Intrinsics */
+#if __ARM_FEATURE_TME
+
+#define _TMFAILURE_REASON 0x00007fffu
+#define _TMFAILURE_RTRY 0x00008000u
+#define _TMFAILURE_CNCL 0x00010000u
+#define _TMFAILURE_MEM 0x00020000u
+#define _TMFAILURE_IMP 0x00040000u
+#define _TMFAILURE_ERR 0x00080000u
+#define _TMFAILURE_SIZE 0x00100000u
+#define _TMFAILURE_NEST 0x00200000u
+#define _TMFAILURE_DBG 0x00400000u
+#define _TMFAILURE_INT 0x00800000u
+#define _TMFAILURE_TRIVIAL 0x01000000u
+
+#define __tstart() __builtin_arm_tstart()
+#define __tcommit() __builtin_arm_tcommit()
+#define __tcancel(__arg) __builtin_arm_tcancel(__arg)
+#define __ttest() __builtin_arm_ttest()
+
+#endif /* __ARM_FEATURE_TME */
+
#if defined(__cplusplus)
}
#endif
diff --git a/lib/Headers/avx512fintrin.h b/lib/Headers/avx512fintrin.h
index 132761f9ef5c..698e477fe5f3 100644
--- a/lib/Headers/avx512fintrin.h
+++ b/lib/Headers/avx512fintrin.h
@@ -7658,13 +7658,13 @@ _mm512_maskz_getexp_ps (__mmask16 __U, __m512 __A)
#define _mm512_i32gather_ps(index, addr, scale) \
(__m512)__builtin_ia32_gathersiv16sf((__v16sf)_mm512_undefined_ps(), \
(void const *)(addr), \
- (__v16sf)(__m512)(index), \
+ (__v16si)(__m512)(index), \
(__mmask16)-1, (int)(scale))
#define _mm512_mask_i32gather_ps(v1_old, mask, index, addr, scale) \
(__m512)__builtin_ia32_gathersiv16sf((__v16sf)(__m512)(v1_old), \
(void const *)(addr), \
- (__v16sf)(__m512)(index), \
+ (__v16si)(__m512)(index), \
(__mmask16)(mask), (int)(scale))
#define _mm512_i32gather_epi32(index, addr, scale) \
@@ -8436,7 +8436,7 @@ _store_mask16(__mmask16 *__A, __mmask16 __B) {
}
static __inline__ void __DEFAULT_FN_ATTRS512
-_mm512_stream_si512 (__m512i * __P, __m512i __A)
+_mm512_stream_si512 (void * __P, __m512i __A)
{
typedef __v8di __v8di_aligned __attribute__((aligned(64)));
__builtin_nontemporal_store((__v8di_aligned)__A, (__v8di_aligned*)__P);
@@ -8450,14 +8450,14 @@ _mm512_stream_load_si512 (void const *__P)
}
static __inline__ void __DEFAULT_FN_ATTRS512
-_mm512_stream_pd (double *__P, __m512d __A)
+_mm512_stream_pd (void *__P, __m512d __A)
{
typedef __v8df __v8df_aligned __attribute__((aligned(64)));
__builtin_nontemporal_store((__v8df_aligned)__A, (__v8df_aligned*)__P);
}
static __inline__ void __DEFAULT_FN_ATTRS512
-_mm512_stream_ps (float *__P, __m512 __A)
+_mm512_stream_ps (void *__P, __m512 __A)
{
typedef __v16sf __v16sf_aligned __attribute__((aligned(64)));
__builtin_nontemporal_store((__v16sf_aligned)__A, (__v16sf_aligned*)__P);
@@ -9659,6 +9659,23 @@ _mm512_mask_reduce_min_ps(__mmask16 __M, __m512 __V) {
}
#undef _mm512_mask_reduce_operator
+/// Moves the least significant 32 bits of a vector of [16 x i32] to a
+/// 32-bit signed integer value.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> VMOVD / MOVD </c> instruction.
+///
+/// \param __A
+/// A vector of [16 x i32]. The least significant 32 bits are moved to the
+/// destination.
+/// \returns A 32-bit signed integer containing the moved value.
+static __inline__ int __DEFAULT_FN_ATTRS512
+_mm512_cvtsi512_si32(__m512i __A) {
+ __v16si __b = (__v16si)__A;
+ return __b[0];
+}
+
#undef __DEFAULT_FN_ATTRS512
#undef __DEFAULT_FN_ATTRS128
#undef __DEFAULT_FN_ATTRS
diff --git a/lib/Headers/bmiintrin.h b/lib/Headers/bmiintrin.h
index b7af62f609ae..841bd84070e8 100644
--- a/lib/Headers/bmiintrin.h
+++ b/lib/Headers/bmiintrin.h
@@ -14,27 +14,13 @@
#ifndef __BMIINTRIN_H
#define __BMIINTRIN_H
-#define _tzcnt_u16(a) (__tzcnt_u16((a)))
-
-#define _andn_u32(a, b) (__andn_u32((a), (b)))
-
-/* _bextr_u32 != __bextr_u32 */
-#define _blsi_u32(a) (__blsi_u32((a)))
-
-#define _blsmsk_u32(a) (__blsmsk_u32((a)))
-
-#define _blsr_u32(a) (__blsr_u32((a)))
-
-#define _tzcnt_u32(a) (__tzcnt_u32((a)))
-
-/* Define the default attributes for the functions in this file. */
-#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("bmi")))
-
/* Allow using the tzcnt intrinsics even for non-BMI targets. Since the TZCNT
instruction behaves as BSF on non-BMI targets, there is code that expects
to use it as a potentially faster version of BSF. */
#define __RELAXED_FN_ATTRS __attribute__((__always_inline__, __nodebug__))
+#define _tzcnt_u16(a) (__tzcnt_u16((a)))
+
/// Counts the number of trailing zero bits in the operand.
///
/// \headerfile <x86intrin.h>
@@ -51,6 +37,94 @@ __tzcnt_u16(unsigned short __X)
return __builtin_ia32_tzcnt_u16(__X);
}
+/// Counts the number of trailing zero bits in the operand.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> TZCNT </c> instruction.
+///
+/// \param __X
+/// An unsigned 32-bit integer whose trailing zeros are to be counted.
+/// \returns An unsigned 32-bit integer containing the number of trailing zero
+/// bits in the operand.
+static __inline__ unsigned int __RELAXED_FN_ATTRS
+__tzcnt_u32(unsigned int __X)
+{
+ return __builtin_ia32_tzcnt_u32(__X);
+}
+
+/// Counts the number of trailing zero bits in the operand.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> TZCNT </c> instruction.
+///
+/// \param __X
+/// An unsigned 32-bit integer whose trailing zeros are to be counted.
+/// \returns An 32-bit integer containing the number of trailing zero bits in
+/// the operand.
+static __inline__ int __RELAXED_FN_ATTRS
+_mm_tzcnt_32(unsigned int __X)
+{
+ return __builtin_ia32_tzcnt_u32(__X);
+}
+
+#define _tzcnt_u32(a) (__tzcnt_u32((a)))
+
+#ifdef __x86_64__
+
+/// Counts the number of trailing zero bits in the operand.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> TZCNT </c> instruction.
+///
+/// \param __X
+/// An unsigned 64-bit integer whose trailing zeros are to be counted.
+/// \returns An unsigned 64-bit integer containing the number of trailing zero
+/// bits in the operand.
+static __inline__ unsigned long long __RELAXED_FN_ATTRS
+__tzcnt_u64(unsigned long long __X)
+{
+ return __builtin_ia32_tzcnt_u64(__X);
+}
+
+/// Counts the number of trailing zero bits in the operand.
+///
+/// \headerfile <x86intrin.h>
+///
+/// This intrinsic corresponds to the <c> TZCNT </c> instruction.
+///
+/// \param __X
+/// An unsigned 64-bit integer whose trailing zeros are to be counted.
+/// \returns An 64-bit integer containing the number of trailing zero bits in
+/// the operand.
+static __inline__ long long __RELAXED_FN_ATTRS
+_mm_tzcnt_64(unsigned long long __X)
+{
+ return __builtin_ia32_tzcnt_u64(__X);
+}
+
+#define _tzcnt_u64(a) (__tzcnt_u64((a)))
+
+#endif /* __x86_64__ */
+
+#undef __RELAXED_FN_ATTRS
+
+#if !defined(_MSC_VER) || __has_feature(modules) || defined(__BMI__)
+
+/* Define the default attributes for the functions in this file. */
+#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("bmi")))
+
+#define _andn_u32(a, b) (__andn_u32((a), (b)))
+
+/* _bextr_u32 != __bextr_u32 */
+#define _blsi_u32(a) (__blsi_u32((a)))
+
+#define _blsmsk_u32(a) (__blsmsk_u32((a)))
+
+#define _blsr_u32(a) (__blsr_u32((a)))
+
/// Performs a bitwise AND of the second operand with the one's
/// complement of the first operand.
///
@@ -169,38 +243,6 @@ __blsr_u32(unsigned int __X)
return __X & (__X - 1);
}
-/// Counts the number of trailing zero bits in the operand.
-///
-/// \headerfile <x86intrin.h>
-///
-/// This intrinsic corresponds to the <c> TZCNT </c> instruction.
-///
-/// \param __X
-/// An unsigned 32-bit integer whose trailing zeros are to be counted.
-/// \returns An unsigned 32-bit integer containing the number of trailing zero
-/// bits in the operand.
-static __inline__ unsigned int __RELAXED_FN_ATTRS
-__tzcnt_u32(unsigned int __X)
-{
- return __builtin_ia32_tzcnt_u32(__X);
-}
-
-/// Counts the number of trailing zero bits in the operand.
-///
-/// \headerfile <x86intrin.h>
-///
-/// This intrinsic corresponds to the <c> TZCNT </c> instruction.
-///
-/// \param __X
-/// An unsigned 32-bit integer whose trailing zeros are to be counted.
-/// \returns An 32-bit integer containing the number of trailing zero bits in
-/// the operand.
-static __inline__ int __RELAXED_FN_ATTRS
-_mm_tzcnt_32(unsigned int __X)
-{
- return __builtin_ia32_tzcnt_u32(__X);
-}
-
#ifdef __x86_64__
#define _andn_u64(a, b) (__andn_u64((a), (b)))
@@ -212,8 +254,6 @@ _mm_tzcnt_32(unsigned int __X)
#define _blsr_u64(a) (__blsr_u64((a)))
-#define _tzcnt_u64(a) (__tzcnt_u64((a)))
-
/// Performs a bitwise AND of the second operand with the one's
/// complement of the first operand.
///
@@ -332,41 +372,10 @@ __blsr_u64(unsigned long long __X)
return __X & (__X - 1);
}
-/// Counts the number of trailing zero bits in the operand.
-///
-/// \headerfile <x86intrin.h>
-///
-/// This intrinsic corresponds to the <c> TZCNT </c> instruction.
-///
-/// \param __X
-/// An unsigned 64-bit integer whose trailing zeros are to be counted.
-/// \returns An unsigned 64-bit integer containing the number of trailing zero
-/// bits in the operand.
-static __inline__ unsigned long long __RELAXED_FN_ATTRS
-__tzcnt_u64(unsigned long long __X)
-{
- return __builtin_ia32_tzcnt_u64(__X);
-}
-
-/// Counts the number of trailing zero bits in the operand.
-///
-/// \headerfile <x86intrin.h>
-///
-/// This intrinsic corresponds to the <c> TZCNT </c> instruction.
-///
-/// \param __X
-/// An unsigned 64-bit integer whose trailing zeros are to be counted.
-/// \returns An 64-bit integer containing the number of trailing zero bits in
-/// the operand.
-static __inline__ long long __RELAXED_FN_ATTRS
-_mm_tzcnt_64(unsigned long long __X)
-{
- return __builtin_ia32_tzcnt_u64(__X);
-}
-
#endif /* __x86_64__ */
#undef __DEFAULT_FN_ATTRS
-#undef __RELAXED_FN_ATTRS
+
+#endif /* !defined(_MSC_VER) || __has_feature(modules) || defined(__BMI__) */
#endif /* __BMIINTRIN_H */
diff --git a/lib/Headers/cpuid.h b/lib/Headers/cpuid.h
index 02ffac26c0b3..4ddd64847c32 100644
--- a/lib/Headers/cpuid.h
+++ b/lib/Headers/cpuid.h
@@ -38,8 +38,8 @@
#define signature_TM2_ecx 0x3638784d
/* NSC: "Geode by NSC" */
#define signature_NSC_ebx 0x646f6547
-#define signature_NSC_edx 0x43534e20
-#define signature_NSC_ecx 0x79622065
+#define signature_NSC_edx 0x79622065
+#define signature_NSC_ecx 0x43534e20
/* NEXGEN: "NexGenDriven" */
#define signature_NEXGEN_ebx 0x4778654e
#define signature_NEXGEN_edx 0x72446e65
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index 3d55f5f2710f..c8fefdfc792a 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -4029,7 +4029,7 @@ _mm_storeu_si128(__m128i_u *__p, __m128i __b)
/// \param __b
/// A 128-bit integer vector containing the value to be stored.
static __inline__ void __DEFAULT_FN_ATTRS
-_mm_storeu_si64(void const *__p, __m128i __b)
+_mm_storeu_si64(void *__p, __m128i __b)
{
struct __storeu_si64 {
long long __v;
@@ -4050,7 +4050,7 @@ _mm_storeu_si64(void const *__p, __m128i __b)
/// \param __b
/// A 128-bit integer vector containing the value to be stored.
static __inline__ void __DEFAULT_FN_ATTRS
-_mm_storeu_si32(void const *__p, __m128i __b)
+_mm_storeu_si32(void *__p, __m128i __b)
{
struct __storeu_si32 {
int __v;
@@ -4071,7 +4071,7 @@ _mm_storeu_si32(void const *__p, __m128i __b)
/// \param __b
/// A 128-bit integer vector containing the value to be stored.
static __inline__ void __DEFAULT_FN_ATTRS
-_mm_storeu_si16(void const *__p, __m128i __b)
+_mm_storeu_si16(void *__p, __m128i __b)
{
struct __storeu_si16 {
short __v;
diff --git a/lib/Headers/ia32intrin.h b/lib/Headers/ia32intrin.h
index 8e38df73187d..79b7f0655cf0 100644
--- a/lib/Headers/ia32intrin.h
+++ b/lib/Headers/ia32intrin.h
@@ -195,6 +195,74 @@ __writeeflags(unsigned int __f)
}
#endif /* !__x86_64__ */
+/** Cast a 32-bit float value to a 32-bit unsigned integer value
+ *
+ * \headerfile <x86intrin.h>
+ * This intrinsic corresponds to the <c> VMOVD / MOVD </c> instruction in x86_64,
+ * and corresponds to the <c> VMOVL / MOVL </c> instruction in ia32.
+ *
+ * \param __A
+ * A 32-bit float value.
+ * \returns a 32-bit unsigned integer containing the converted value.
+ */
+static __inline__ unsigned int __attribute__((__always_inline__))
+_castf32_u32(float __A) {
+ unsigned int D;
+ __builtin_memcpy(&D, &__A, sizeof(__A));
+ return D;
+}
+
+/** Cast a 64-bit float value to a 64-bit unsigned integer value
+ *
+ * \headerfile <x86intrin.h>
+ * This intrinsic corresponds to the <c> VMOVQ / MOVQ </c> instruction in x86_64,
+ * and corresponds to the <c> VMOVL / MOVL </c> instruction in ia32.
+ *
+ * \param __A
+ * A 64-bit float value.
+ * \returns a 64-bit unsigned integer containing the converted value.
+ */
+static __inline__ unsigned long long __attribute__((__always_inline__))
+_castf64_u64(double __A) {
+ unsigned long long D;
+ __builtin_memcpy(&D, &__A, sizeof(__A));
+ return D;
+}
+
+/** Cast a 32-bit unsigned integer value to a 32-bit float value
+ *
+ * \headerfile <x86intrin.h>
+ * This intrinsic corresponds to the <c> VMOVQ / MOVQ </c> instruction in x86_64,
+ * and corresponds to the <c> FLDS </c> instruction in ia32.
+ *
+ * \param __A
+ * A 32-bit unsigned integer value.
+ * \returns a 32-bit float value containing the converted value.
+ */
+static __inline__ float __attribute__((__always_inline__))
+_castu32_f32(unsigned int __A) {
+ float D;
+ __builtin_memcpy(&D, &__A, sizeof(__A));
+ return D;
+}
+
+/** Cast a 64-bit unsigned integer value to a 64-bit float value
+ *
+ * \headerfile <x86intrin.h>
+ * This intrinsic corresponds to the <c> VMOVQ / MOVQ </c> instruction in x86_64,
+ * and corresponds to the <c> FLDL </c> instruction in ia32.
+ *
+ * \param __A
+ * A 64-bit unsigned integer value.
+ * \returns a 64-bit float value containing the converted value.
+ */
+static __inline__ double __attribute__((__always_inline__))
+_castu64_f64(unsigned long long __A) {
+ double D;
+ __builtin_memcpy(&D, &__A, sizeof(__A));
+ return D;
+}
+
/** Adds the unsigned integer operand to the CRC-32C checksum of the
* unsigned char operand.
*
diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h
index 7555ad82fac7..ae900ee85b76 100644
--- a/lib/Headers/immintrin.h
+++ b/lib/Headers/immintrin.h
@@ -64,9 +64,8 @@
#include <vpclmulqdqintrin.h>
#endif
-#if !defined(_MSC_VER) || __has_feature(modules) || defined(__BMI__)
+/* No feature check desired due to internal checks */
#include <bmiintrin.h>
-#endif
#if !defined(_MSC_VER) || __has_feature(modules) || defined(__BMI2__)
#include <bmi2intrin.h>
diff --git a/lib/Headers/opencl-c-base.h b/lib/Headers/opencl-c-base.h
index a82954ddd326..430e07d36f62 100644
--- a/lib/Headers/opencl-c-base.h
+++ b/lib/Headers/opencl-c-base.h
@@ -126,7 +126,7 @@ typedef double double8 __attribute__((ext_vector_type(8)));
typedef double double16 __attribute__((ext_vector_type(16)));
#endif
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
#define NULL ((void*)0)
#endif
@@ -276,7 +276,7 @@ typedef uint cl_mem_fence_flags;
*/
#define CLK_GLOBAL_MEM_FENCE 0x02
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
typedef enum memory_scope {
memory_scope_work_item = __OPENCL_MEMORY_SCOPE_WORK_ITEM,
@@ -288,9 +288,6 @@ typedef enum memory_scope {
#endif
} memory_scope;
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
-
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
/**
* Queue a memory fence to ensure correct ordering of memory
* operations between work-items of a work-group to
@@ -313,7 +310,7 @@ typedef enum memory_order
memory_order_seq_cst = __ATOMIC_SEQ_CST
} memory_order;
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// OpenCL v1.1 s6.11.3, v1.2 s6.12.14, v2.0 s6.13.14 - Image Read and Write Functions
@@ -389,14 +386,10 @@ typedef enum memory_order
#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
// OpenCL v2.0 s6.13.16 - Pipe Functions
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
#define CLK_NULL_RESERVE_ID (__builtin_astype(((void*)(__SIZE_MAX__)), reserve_id_t))
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
-
// OpenCL v2.0 s6.13.17 - Enqueue Kernels
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
-
#define CL_COMPLETE 0x0
#define CL_RUNNING 0x1
#define CL_SUBMITTED 0x2
@@ -413,7 +406,7 @@ typedef enum memory_order
#define CLK_OUT_OF_RESOURCES -5
#define CLK_NULL_QUEUE 0
-#define CLK_NULL_EVENT (__builtin_astype(((void*)(__SIZE_MAX__)), clk_event_t))
+#define CLK_NULL_EVENT (__builtin_astype(((__SIZE_MAX__)), clk_event_t))
// execution model related definitions
#define CLK_ENQUEUE_FLAGS_NO_WAIT 0x0
@@ -435,7 +428,7 @@ typedef struct {
size_t localWorkSize[MAX_WORK_DIM];
} ndrange_t;
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
#ifdef cl_intel_device_side_avc_motion_estimation
#pragma OPENCL EXTENSION cl_intel_device_side_avc_motion_estimation : begin
diff --git a/lib/Headers/opencl-c.h b/lib/Headers/opencl-c.h
index 4207c53ccedb..06c5ab6a72f0 100644
--- a/lib/Headers/opencl-c.h
+++ b/lib/Headers/opencl-c.h
@@ -11,11 +11,11 @@
#include "opencl-c-base.h"
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
#ifndef cl_khr_depth_images
#define cl_khr_depth_images
#endif //cl_khr_depth_images
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
#if __OPENCL_C_VERSION__ < CL_VERSION_2_0
#ifdef cl_khr_3d_image_writes
@@ -23,10 +23,10 @@
#endif //cl_khr_3d_image_writes
#endif //__OPENCL_C_VERSION__ < CL_VERSION_2_0
-#if __OPENCL_C_VERSION__ >= CL_VERSION_1_2
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2)
#pragma OPENCL EXTENSION cl_intel_planar_yuv : begin
#pragma OPENCL EXTENSION cl_intel_planar_yuv : end
-#endif // __OPENCL_C_VERSION__ >= CL_VERSION_1_2
+#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2)
#define __ovld __attribute__((overloadable))
#define __conv __attribute__((convergent))
@@ -6517,11 +6517,11 @@ size_t __ovld __cnfn get_group_id(uint dimindx);
*/
size_t __ovld __cnfn get_global_offset(uint dimindx);
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
size_t __ovld get_enqueued_local_size(uint dimindx);
size_t __ovld get_global_linear_id(void);
size_t __ovld get_local_linear_id(void);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// OpenCL v1.1 s6.11.2, v1.2 s6.12.2, v2.0 s6.13.2 - Math functions
@@ -7352,7 +7352,7 @@ half16 __ovld __cnfn fmod(half16 x, half16 y);
* Returns fmin(x - floor (x), 0x1.fffffep-1f ).
* floor(x) is returned in iptr.
*/
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
float __ovld fract(float x, float *iptr);
float2 __ovld fract(float2 x, float2 *iptr);
float3 __ovld fract(float3 x, float3 *iptr);
@@ -7434,7 +7434,7 @@ half4 __ovld fract(half4 x, __private half4 *iptr);
half8 __ovld fract(half8 x, __private half8 *iptr);
half16 __ovld fract(half16 x, __private half16 *iptr);
#endif //cl_khr_fp16
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Extract mantissa and exponent from x. For each
@@ -7442,7 +7442,7 @@ half16 __ovld fract(half16 x, __private half16 *iptr);
* magnitude in the interval [1/2, 1) or 0. Each
* component of x equals mantissa returned * 2^exp.
*/
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
float __ovld frexp(float x, int *exp);
float2 __ovld frexp(float2 x, int2 *exp);
float3 __ovld frexp(float3 x, int3 *exp);
@@ -7524,7 +7524,7 @@ half4 __ovld frexp(half4 x, __private int4 *exp);
half8 __ovld frexp(half8 x, __private int8 *exp);
half16 __ovld frexp(half16 x, __private int16 *exp);
#endif //cl_khr_fp16
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Compute the value of the square root of x^2 + y^2
@@ -7649,7 +7649,7 @@ half8 __ovld __cnfn lgamma(half8 x);
half16 __ovld __cnfn lgamma(half16 x);
#endif //cl_khr_fp16
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
float __ovld lgamma_r(float x, int *signp);
float2 __ovld lgamma_r(float2 x, int2 *signp);
float3 __ovld lgamma_r(float3 x, int3 *signp);
@@ -7731,7 +7731,7 @@ half4 __ovld lgamma_r(half4 x, __private int4 *signp);
half8 __ovld lgamma_r(half8 x, __private int8 *signp);
half16 __ovld lgamma_r(half16 x, __private int16 *signp);
#endif //cl_khr_fp16
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Compute natural logarithm.
@@ -7955,7 +7955,7 @@ half16 __ovld __cnfn minmag(half16 x, half16 y);
* the argument. It stores the integral part in the object
* pointed to by iptr.
*/
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
float __ovld modf(float x, float *iptr);
float2 __ovld modf(float2 x, float2 *iptr);
float3 __ovld modf(float3 x, float3 *iptr);
@@ -8037,7 +8037,7 @@ half4 __ovld modf(half4 x, __private half4 *iptr);
half8 __ovld modf(half8 x, __private half8 *iptr);
half16 __ovld modf(half16 x, __private half16 *iptr);
#endif //cl_khr_fp16
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Returns a quiet NaN. The nancode may be placed
@@ -8215,7 +8215,7 @@ half16 __ovld __cnfn remainder(half16 x, half16 y);
* sign as x/y. It stores this signed value in the object
* pointed to by quo.
*/
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
float __ovld remquo(float x, float y, int *quo);
float2 __ovld remquo(float2 x, float2 y, int2 *quo);
float3 __ovld remquo(float3 x, float3 y, int3 *quo);
@@ -8298,7 +8298,7 @@ half4 __ovld remquo(half4 x, half4 y, __private int4 *quo);
half8 __ovld remquo(half8 x, half8 y, __private int8 *quo);
half16 __ovld remquo(half16 x, half16 y, __private int16 *quo);
#endif //cl_khr_fp16
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Round to integral value (using round to nearest
* even rounding mode) in floating-point format.
@@ -8439,7 +8439,7 @@ half16 __ovld __cnfn sin(half16);
* is the return value and computed cosine is returned
* in cosval.
*/
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
float __ovld sincos(float x, float *cosval);
float2 __ovld sincos(float2 x, float2 *cosval);
float3 __ovld sincos(float3 x, float3 *cosval);
@@ -8521,7 +8521,7 @@ half4 __ovld sincos(half4 x, __private half4 *cosval);
half8 __ovld sincos(half8 x, __private half8 *cosval);
half16 __ovld sincos(half16 x, __private half16 *cosval);
#endif //cl_khr_fp16
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Compute hyperbolic sine.
@@ -9446,7 +9446,7 @@ ulong16 __ovld __cnfn clz(ulong16 x);
* returns the size in bits of the type of x or
* component type of x, if x is a vector.
*/
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
char __ovld ctz(char x);
uchar __ovld ctz(uchar x);
char2 __ovld ctz(char2 x);
@@ -9495,7 +9495,7 @@ long8 __ovld ctz(long8 x);
ulong8 __ovld ctz(ulong8 x);
long16 __ovld ctz(long16 x);
ulong16 __ovld ctz(ulong16 x);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Returns mul_hi(a, b) + c.
@@ -11340,7 +11340,7 @@ half8 __ovld vload8(size_t offset, const __constant half *p);
half16 __ovld vload16(size_t offset, const __constant half *p);
#endif //cl_khr_fp16
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
char2 __ovld vload2(size_t offset, const char *p);
uchar2 __ovld vload2(size_t offset, const uchar *p);
short2 __ovld vload2(size_t offset, const short *p);
@@ -11578,9 +11578,9 @@ half4 __ovld vload4(size_t offset, const __private half *p);
half8 __ovld vload8(size_t offset, const __private half *p);
half16 __ovld vload16(size_t offset, const __private half *p);
#endif //cl_khr_fp16
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
void __ovld vstore2(char2 data, size_t offset, char *p);
void __ovld vstore2(uchar2 data, size_t offset, uchar *p);
void __ovld vstore2(short2 data, size_t offset, short *p);
@@ -11814,7 +11814,7 @@ void __ovld vstore4(half4 data, size_t offset, __private half *p);
void __ovld vstore8(half8 data, size_t offset, __private half *p);
void __ovld vstore16(half16 data, size_t offset, __private half *p);
#endif //cl_khr_fp16
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Read sizeof (half) bytes of data from address
@@ -11825,13 +11825,13 @@ void __ovld vstore16(half16 data, size_t offset, __private half *p);
* must be 16-bit aligned.
*/
float __ovld vload_half(size_t offset, const __constant half *p);
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
float __ovld vload_half(size_t offset, const half *p);
#else
float __ovld vload_half(size_t offset, const __global half *p);
float __ovld vload_half(size_t offset, const __local half *p);
float __ovld vload_half(size_t offset, const __private half *p);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Read sizeof (halfn) bytes of data from address
@@ -11846,7 +11846,7 @@ float3 __ovld vload_half3(size_t offset, const __constant half *p);
float4 __ovld vload_half4(size_t offset, const __constant half *p);
float8 __ovld vload_half8(size_t offset, const __constant half *p);
float16 __ovld vload_half16(size_t offset, const __constant half *p);
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
float2 __ovld vload_half2(size_t offset, const half *p);
float3 __ovld vload_half3(size_t offset, const half *p);
float4 __ovld vload_half4(size_t offset, const half *p);
@@ -11868,7 +11868,7 @@ float3 __ovld vload_half3(size_t offset, const __private half *p);
float4 __ovld vload_half4(size_t offset, const __private half *p);
float8 __ovld vload_half8(size_t offset, const __private half *p);
float16 __ovld vload_half16(size_t offset, const __private half *p);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* The float value given by data is first
@@ -11881,7 +11881,7 @@ float16 __ovld vload_half16(size_t offset, const __private half *p);
* The default current rounding mode is round to
* nearest even.
*/
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
void __ovld vstore_half(float data, size_t offset, half *p);
void __ovld vstore_half_rte(float data, size_t offset, half *p);
void __ovld vstore_half_rtz(float data, size_t offset, half *p);
@@ -11927,7 +11927,7 @@ void __ovld vstore_half_rtz(double data, size_t offset, __private half *p);
void __ovld vstore_half_rtp(double data, size_t offset, __private half *p);
void __ovld vstore_half_rtn(double data, size_t offset, __private half *p);
#endif //cl_khr_fp64
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* The floatn value given by data is converted to
@@ -11940,7 +11940,7 @@ void __ovld vstore_half_rtn(double data, size_t offset, __private half *p);
* The default current rounding mode is round to
* nearest even.
*/
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
void __ovld vstore_half2(float2 data, size_t offset, half *p);
void __ovld vstore_half3(float3 data, size_t offset, half *p);
void __ovld vstore_half4(float4 data, size_t offset, half *p);
@@ -12146,7 +12146,7 @@ void __ovld vstore_half4_rtn(double4 data, size_t offset, __private half *p);
void __ovld vstore_half8_rtn(double8 data, size_t offset, __private half *p);
void __ovld vstore_half16_rtn(double16 data, size_t offset, __private half *p);
#endif //cl_khr_fp64
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* For n = 1, 2, 4, 8 and 16 read sizeof (halfn)
@@ -12167,7 +12167,7 @@ float3 __ovld vloada_half3(size_t offset, const __constant half *p);
float4 __ovld vloada_half4(size_t offset, const __constant half *p);
float8 __ovld vloada_half8(size_t offset, const __constant half *p);
float16 __ovld vloada_half16(size_t offset, const __constant half *p);
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
float __ovld vloada_half(size_t offset, const half *p);
float2 __ovld vloada_half2(size_t offset, const half *p);
float3 __ovld vloada_half3(size_t offset, const half *p);
@@ -12193,7 +12193,7 @@ float3 __ovld vloada_half3(size_t offset, const __private half *p);
float4 __ovld vloada_half4(size_t offset, const __private half *p);
float8 __ovld vloada_half8(size_t offset, const __private half *p);
float16 __ovld vloada_half16(size_t offset, const __private half *p);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* The floatn value given by data is converted to
@@ -12211,7 +12211,7 @@ float16 __ovld vloada_half16(size_t offset, const __private half *p);
* mode. The default current rounding mode is
* round to nearest even.
*/
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
void __ovld vstorea_half(float data, size_t offset, half *p);
void __ovld vstorea_half2(float2 data, size_t offset, half *p);
void __ovld vstorea_half3(float3 data, size_t offset, half *p);
@@ -12496,7 +12496,7 @@ void __ovld vstorea_half4_rtn(double4 data,size_t offset, __private half *p);
void __ovld vstorea_half8_rtn(double8 data,size_t offset, __private half *p);
void __ovld vstorea_half16_rtn(double16 data,size_t offset, __private half *p);
#endif //cl_khr_fp64
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// OpenCL v1.1 s6.11.8, v1.2 s6.12.8, v2.0 s6.13.8 - Synchronization Functions
@@ -12532,10 +12532,10 @@ void __ovld vstorea_half16_rtn(double16 data,size_t offset, __private half *p);
void __ovld __conv barrier(cl_mem_fence_flags flags);
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
void __ovld __conv work_group_barrier(cl_mem_fence_flags flags, memory_scope scope);
void __ovld __conv work_group_barrier(cl_mem_fence_flags flags);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// OpenCL v1.1 s6.11.9, v1.2 s6.12.9 - Explicit Memory Fence Functions
@@ -12580,7 +12580,7 @@ void __ovld write_mem_fence(cl_mem_fence_flags flags);
// OpenCL v2.0 s6.13.9 - Address Space Qualifier Functions
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
cl_mem_fence_flags __ovld get_fence(const void *ptr);
cl_mem_fence_flags __ovld get_fence(void *ptr);
@@ -12591,7 +12591,7 @@ cl_mem_fence_flags __ovld get_fence(void *ptr);
* where gentype is builtin type or user defined type.
*/
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// OpenCL v1.1 s6.11.10, v1.2 s6.12.10, v2.0 s6.13.10 - Async Copies from Global to Local Memory, Local to Global Memory, and Prefetch
@@ -13371,7 +13371,7 @@ unsigned long __ovld atom_xor(volatile __local unsigned long *p, unsigned long v
// OpenCL v2.0 s6.13.11 - Atomics Functions
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// double atomics support requires extensions cl_khr_int64_base_atomics and cl_khr_int64_extended_atomics
#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics)
@@ -13692,7 +13692,7 @@ void __ovld atomic_flag_clear(volatile atomic_flag *object);
void __ovld atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order);
void __ovld atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order, memory_scope scope);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// OpenCL v1.1 s6.11.12, v1.2 s6.12.12, v2.0 s6.13.12 - Miscellaneous Vector Functions
@@ -14186,7 +14186,7 @@ half16 __ovld __cnfn shuffle2(half8 x, half8 y, ushort16 mask);
half16 __ovld __cnfn shuffle2(half16 x, half16 y, ushort16 mask);
#endif //cl_khr_fp16
-#if __OPENCL_C_VERSION__ >= CL_VERSION_1_2
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2)
// OpenCL v1.2 s6.12.13, v2.0 s6.13.13 - printf
int printf(__constant const char* st, ...) __attribute__((format(printf, 1, 2)));
@@ -14307,7 +14307,7 @@ int4 __purefn __ovld read_imagei(read_only image3d_t image, sampler_t sampler, f
uint4 __purefn __ovld read_imageui(read_only image3d_t image, sampler_t sampler, int4 coord);
uint4 __purefn __ovld read_imageui(read_only image3d_t image, sampler_t sampler, float4 coord);
-#if __OPENCL_C_VERSION__ >= CL_VERSION_1_2
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2)
float4 __purefn __ovld read_imagef(read_only image2d_array_t image_array, sampler_t sampler, int4 coord);
float4 __purefn __ovld read_imagef(read_only image2d_array_t image_array, sampler_t sampler, float4 coord);
@@ -14315,7 +14315,7 @@ int4 __purefn __ovld read_imagei(read_only image2d_array_t image_array, sampler_
int4 __purefn __ovld read_imagei(read_only image2d_array_t image_array, sampler_t sampler, float4 coord);
uint4 __purefn __ovld read_imageui(read_only image2d_array_t image_array, sampler_t sampler, int4 coord);
uint4 __purefn __ovld read_imageui(read_only image2d_array_t image_array, sampler_t sampler, float4 coord);
-#endif // __OPENCL_C_VERSION__ >= CL_VERSION_1_2
+#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2)
float4 __purefn __ovld read_imagef(read_only image1d_t image, sampler_t sampler, int coord);
float4 __purefn __ovld read_imagef(read_only image1d_t image, sampler_t sampler, float coord);
@@ -14325,7 +14325,7 @@ int4 __purefn __ovld read_imagei(read_only image1d_t image, sampler_t sampler, f
uint4 __purefn __ovld read_imageui(read_only image1d_t image, sampler_t sampler, int coord);
uint4 __purefn __ovld read_imageui(read_only image1d_t image, sampler_t sampler, float coord);
-#if __OPENCL_C_VERSION__ >= CL_VERSION_1_2
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2)
float4 __purefn __ovld read_imagef(read_only image1d_array_t image_array, sampler_t sampler, int2 coord);
float4 __purefn __ovld read_imagef(read_only image1d_array_t image_array, sampler_t sampler, float2 coord);
@@ -14333,7 +14333,7 @@ int4 __purefn __ovld read_imagei(read_only image1d_array_t image_array, sampler_
int4 __purefn __ovld read_imagei(read_only image1d_array_t image_array, sampler_t sampler, float2 coord);
uint4 __purefn __ovld read_imageui(read_only image1d_array_t image_array, sampler_t sampler, int2 coord);
uint4 __purefn __ovld read_imageui(read_only image1d_array_t image_array, sampler_t sampler, float2 coord);
-#endif // __OPENCL_C_VERSION__ >= CL_VERSION_1_2
+#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2)
#ifdef cl_khr_depth_images
float __purefn __ovld read_imagef(read_only image2d_depth_t image, sampler_t sampler, float2 coord);
@@ -14358,7 +14358,7 @@ float __purefn __ovld read_imagef(read_only image2d_array_msaa_depth_t image, in
#endif //cl_khr_gl_msaa_sharing
// OpenCL Extension v2.0 s9.18 - Mipmaps
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
#ifdef cl_khr_mipmap_image
float4 __purefn __ovld read_imagef(read_only image1d_t image, sampler_t sampler, float coord, float lod);
@@ -14410,9 +14410,9 @@ int4 __purefn __ovld read_imagei(read_only image3d_t image, sampler_t sampler, f
uint4 __purefn __ovld read_imageui(read_only image3d_t image, sampler_t sampler, float4 coord, float4 gradientX, float4 gradientY);
#endif //cl_khr_mipmap_image
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
-#if __OPENCL_C_VERSION__ >= CL_VERSION_1_2
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2)
/**
* Sampler-less Image Access
@@ -14447,7 +14447,7 @@ float4 __purefn __ovld read_imagef(read_only image3d_t image, int4 coord);
int4 __purefn __ovld read_imagei(read_only image3d_t image, int4 coord);
uint4 __purefn __ovld read_imageui(read_only image3d_t image, int4 coord);
-#endif // __OPENCL_C_VERSION__ >= CL_VERSION_1_2
+#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2)
// Image read functions returning half4 type
#ifdef cl_khr_fp16
@@ -14457,7 +14457,7 @@ half4 __purefn __ovld read_imageh(read_only image2d_t image, sampler_t sampler,
half4 __purefn __ovld read_imageh(read_only image2d_t image, sampler_t sampler, float2 coord);
half4 __purefn __ovld read_imageh(read_only image3d_t image, sampler_t sampler, int4 coord);
half4 __purefn __ovld read_imageh(read_only image3d_t image, sampler_t sampler, float4 coord);
-#if __OPENCL_C_VERSION__ >= CL_VERSION_1_2
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2)
half4 __purefn __ovld read_imageh(read_only image1d_array_t image, sampler_t sampler, int2 coord);
half4 __purefn __ovld read_imageh(read_only image1d_array_t image, sampler_t sampler, float2 coord);
half4 __purefn __ovld read_imageh(read_only image2d_array_t image, sampler_t sampler, int4 coord);
@@ -14471,11 +14471,11 @@ half4 __purefn __ovld read_imageh(read_only image3d_t image, int4 coord);
half4 __purefn __ovld read_imageh(read_only image1d_array_t image, int2 coord);
half4 __purefn __ovld read_imageh(read_only image2d_array_t image, int4 coord);
half4 __purefn __ovld read_imageh(read_only image1d_buffer_t image, int coord);
-#endif // __OPENCL_C_VERSION__ >= CL_VERSION_1_2
+#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2)
#endif //cl_khr_fp16
// Image read functions for read_write images
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
float4 __purefn __ovld read_imagef(read_write image1d_t image, int coord);
int4 __purefn __ovld read_imagei(read_write image1d_t image, int coord);
uint4 __purefn __ovld read_imageui(read_write image1d_t image, int coord);
@@ -14518,7 +14518,7 @@ float __purefn __ovld read_imagef(read_write image2d_msaa_depth_t image, int2 co
float __purefn __ovld read_imagef(read_write image2d_array_msaa_depth_t image, int4 coord, int sample);
#endif //cl_khr_gl_msaa_sharing
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
#ifdef cl_khr_mipmap_image
float4 __purefn __ovld read_imagef(read_write image1d_t image, sampler_t sampler, float coord, float lod);
int4 __purefn __ovld read_imagei(read_write image1d_t image, sampler_t sampler, float coord, float lod);
@@ -14569,7 +14569,7 @@ int4 __purefn __ovld read_imagei(read_write image3d_t image, sampler_t sampler,
uint4 __purefn __ovld read_imageui(read_write image3d_t image, sampler_t sampler, float4 coord, float4 gradientX, float4 gradientY);
#endif //cl_khr_mipmap_image
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// Image read functions returning half4 type
#ifdef cl_khr_fp16
@@ -14580,7 +14580,7 @@ half4 __purefn __ovld read_imageh(read_write image1d_array_t image, int2 coord);
half4 __purefn __ovld read_imageh(read_write image2d_array_t image, int4 coord);
half4 __purefn __ovld read_imageh(read_write image1d_buffer_t image, int coord);
#endif //cl_khr_fp16
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Write color value to location specified by coordinate
@@ -14681,7 +14681,7 @@ void __ovld write_imagef(write_only image2d_array_depth_t image, int4 coord, flo
#endif //cl_khr_depth_images
// OpenCL Extension v2.0 s9.18 - Mipmaps
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
#ifdef cl_khr_mipmap_image
void __ovld write_imagef(write_only image1d_t image, int coord, int lod, float4 color);
void __ovld write_imagei(write_only image1d_t image, int coord, int lod, int4 color);
@@ -14708,7 +14708,7 @@ void __ovld write_imagei(write_only image3d_t image, int4 coord, int lod, int4 c
void __ovld write_imageui(write_only image3d_t image, int4 coord, int lod, uint4 color);
#endif
#endif //cl_khr_mipmap_image
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// Image write functions for half4 type
#ifdef cl_khr_fp16
@@ -14723,7 +14723,7 @@ void __ovld write_imageh(write_only image1d_buffer_t image, int coord, half4 col
#endif //cl_khr_fp16
// Image write functions for read_write images
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
void __ovld write_imagef(read_write image2d_t image, int2 coord, float4 color);
void __ovld write_imagei(read_write image2d_t image, int2 coord, int4 color);
void __ovld write_imageui(read_write image2d_t image, int2 coord, uint4 color);
@@ -14755,7 +14755,7 @@ void __ovld write_imagef(read_write image2d_depth_t image, int2 coord, float col
void __ovld write_imagef(read_write image2d_array_depth_t image, int4 coord, float color);
#endif //cl_khr_depth_images
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
#ifdef cl_khr_mipmap_image
void __ovld write_imagef(read_write image1d_t image, int coord, int lod, float4 color);
void __ovld write_imagei(read_write image1d_t image, int coord, int lod, int4 color);
@@ -14782,7 +14782,7 @@ void __ovld write_imagei(read_write image3d_t image, int4 coord, int lod, int4 c
void __ovld write_imageui(read_write image3d_t image, int4 coord, int lod, uint4 color);
#endif
#endif //cl_khr_mipmap_image
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// Image write functions for half4 type
#ifdef cl_khr_fp16
@@ -14795,7 +14795,7 @@ void __ovld write_imageh(read_write image1d_array_t image, int2 coord, half4 col
void __ovld write_imageh(read_write image2d_array_t image, int4 coord, half4 color);
void __ovld write_imageh(read_write image1d_buffer_t image, int coord, half4 color);
#endif //cl_khr_fp16
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// Note: In OpenCL v1.0/1.1/1.2, image argument of image query builtin functions does not have
// access qualifier, which by default assume read_only access qualifier. Image query builtin
@@ -14843,7 +14843,7 @@ int __ovld __cnfn get_image_width(write_only image2d_array_msaa_t image);
int __ovld __cnfn get_image_width(write_only image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
int __ovld __cnfn get_image_width(read_write image1d_t image);
int __ovld __cnfn get_image_width(read_write image1d_buffer_t image);
int __ovld __cnfn get_image_width(read_write image2d_t image);
@@ -14860,7 +14860,7 @@ int __ovld __cnfn get_image_width(read_write image2d_msaa_depth_t image);
int __ovld __cnfn get_image_width(read_write image2d_array_msaa_t image);
int __ovld __cnfn get_image_width(read_write image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Return the image height in pixels.
@@ -14895,7 +14895,7 @@ int __ovld __cnfn get_image_height(write_only image2d_array_msaa_t image);
int __ovld __cnfn get_image_height(write_only image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
int __ovld __cnfn get_image_height(read_write image2d_t image);
int __ovld __cnfn get_image_height(read_write image3d_t image);
int __ovld __cnfn get_image_height(read_write image2d_array_t image);
@@ -14909,7 +14909,7 @@ int __ovld __cnfn get_image_height(read_write image2d_msaa_depth_t image);
int __ovld __cnfn get_image_height(read_write image2d_array_msaa_t image);
int __ovld __cnfn get_image_height(read_write image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Return the image depth in pixels.
@@ -14920,12 +14920,12 @@ int __ovld __cnfn get_image_depth(read_only image3d_t image);
int __ovld __cnfn get_image_depth(write_only image3d_t image);
#endif
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
int __ovld __cnfn get_image_depth(read_write image3d_t image);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// OpenCL Extension v2.0 s9.18 - Mipmaps
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
#ifdef cl_khr_mipmap_image
/**
* Return the image miplevels.
@@ -14961,7 +14961,7 @@ int __ovld get_image_num_mip_levels(read_write image2d_array_depth_t image);
int __ovld get_image_num_mip_levels(read_write image2d_depth_t image);
#endif //cl_khr_mipmap_image
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Return the channel data type. Valid values are:
@@ -15018,7 +15018,7 @@ int __ovld __cnfn get_image_channel_data_type(write_only image2d_array_msaa_t im
int __ovld __cnfn get_image_channel_data_type(write_only image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
int __ovld __cnfn get_image_channel_data_type(read_write image1d_t image);
int __ovld __cnfn get_image_channel_data_type(read_write image1d_buffer_t image);
int __ovld __cnfn get_image_channel_data_type(read_write image2d_t image);
@@ -15035,7 +15035,7 @@ int __ovld __cnfn get_image_channel_data_type(read_write image2d_msaa_depth_t im
int __ovld __cnfn get_image_channel_data_type(read_write image2d_array_msaa_t image);
int __ovld __cnfn get_image_channel_data_type(read_write image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Return the image channel order. Valid values are:
@@ -15090,7 +15090,7 @@ int __ovld __cnfn get_image_channel_order(write_only image2d_array_msaa_t image)
int __ovld __cnfn get_image_channel_order(write_only image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
int __ovld __cnfn get_image_channel_order(read_write image1d_t image);
int __ovld __cnfn get_image_channel_order(read_write image1d_buffer_t image);
int __ovld __cnfn get_image_channel_order(read_write image2d_t image);
@@ -15107,7 +15107,7 @@ int __ovld __cnfn get_image_channel_order(read_write image2d_msaa_depth_t image)
int __ovld __cnfn get_image_channel_order(read_write image2d_array_msaa_t image);
int __ovld __cnfn get_image_channel_order(read_write image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Return the 2D image width and height as an int2
@@ -15140,7 +15140,7 @@ int2 __ovld __cnfn get_image_dim(write_only image2d_array_msaa_t image);
int2 __ovld __cnfn get_image_dim(write_only image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
int2 __ovld __cnfn get_image_dim(read_write image2d_t image);
int2 __ovld __cnfn get_image_dim(read_write image2d_array_t image);
#ifdef cl_khr_depth_images
@@ -15153,7 +15153,7 @@ int2 __ovld __cnfn get_image_dim(read_write image2d_msaa_depth_t image);
int2 __ovld __cnfn get_image_dim(read_write image2d_array_msaa_t image);
int2 __ovld __cnfn get_image_dim(read_write image2d_array_msaa_depth_t image);
#endif //cl_khr_gl_msaa_sharing
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Return the 3D image width, height, and depth as an
@@ -15165,9 +15165,9 @@ int4 __ovld __cnfn get_image_dim(read_only image3d_t image);
#ifdef cl_khr_3d_image_writes
int4 __ovld __cnfn get_image_dim(write_only image3d_t image);
#endif
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
int4 __ovld __cnfn get_image_dim(read_write image3d_t image);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Return the image array size.
@@ -15193,7 +15193,7 @@ size_t __ovld __cnfn get_image_array_size(write_only image2d_array_msaa_t image_
size_t __ovld __cnfn get_image_array_size(write_only image2d_array_msaa_depth_t image_array);
#endif //cl_khr_gl_msaa_sharing
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
size_t __ovld __cnfn get_image_array_size(read_write image1d_array_t image_array);
size_t __ovld __cnfn get_image_array_size(read_write image2d_array_t image_array);
#ifdef cl_khr_depth_images
@@ -15203,7 +15203,7 @@ size_t __ovld __cnfn get_image_array_size(read_write image2d_array_depth_t image
size_t __ovld __cnfn get_image_array_size(read_write image2d_array_msaa_t image_array);
size_t __ovld __cnfn get_image_array_size(read_write image2d_array_msaa_depth_t image_array);
#endif //cl_khr_gl_msaa_sharing
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
/**
* Return the number of samples associated with image
@@ -15219,17 +15219,17 @@ int __ovld get_image_num_samples(write_only image2d_msaa_depth_t image);
int __ovld get_image_num_samples(write_only image2d_array_msaa_t image);
int __ovld get_image_num_samples(write_only image2d_array_msaa_depth_t image);
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
int __ovld get_image_num_samples(read_write image2d_msaa_t image);
int __ovld get_image_num_samples(read_write image2d_msaa_depth_t image);
int __ovld get_image_num_samples(read_write image2d_array_msaa_t image);
int __ovld get_image_num_samples(read_write image2d_array_msaa_depth_t image);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
#endif
// OpenCL v2.0 s6.13.15 - Work-group Functions
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
int __ovld __conv work_group_all(int predicate);
int __ovld __conv work_group_any(int predicate);
@@ -15327,16 +15327,16 @@ double __ovld __conv work_group_scan_inclusive_min(double x);
double __ovld __conv work_group_scan_inclusive_max(double x);
#endif //cl_khr_fp64
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// OpenCL v2.0 s6.13.16 - Pipe Functions
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
bool __ovld is_valid_reserve_id(reserve_id_t reserve_id);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// OpenCL v2.0 s6.13.17 - Enqueue Kernels
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
ndrange_t __ovld ndrange_1D(size_t);
ndrange_t __ovld ndrange_1D(size_t, size_t);
@@ -15350,7 +15350,7 @@ ndrange_t __ovld ndrange_3D(const size_t[3]);
ndrange_t __ovld ndrange_3D(const size_t[3], const size_t[3]);
ndrange_t __ovld ndrange_3D(const size_t[3], const size_t[3], const size_t[3]);
-int __ovld enqueue_marker(queue_t, uint, const __private clk_event_t*, __private clk_event_t*);
+int __ovld enqueue_marker(queue_t, uint, const clk_event_t*, clk_event_t*);
void __ovld retain_event(clk_event_t);
@@ -15365,7 +15365,7 @@ bool __ovld is_valid_event (clk_event_t event);
void __ovld capture_event_profiling_info(clk_event_t, clk_profiling_info, __global void* value);
queue_t __ovld get_default_queue(void);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
// OpenCL Extension v2.0 s9.17 - Sub-groups
@@ -15374,16 +15374,16 @@ queue_t __ovld get_default_queue(void);
uint __ovld get_sub_group_size(void);
uint __ovld get_max_sub_group_size(void);
uint __ovld get_num_sub_groups(void);
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
uint __ovld get_enqueued_num_sub_groups(void);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
uint __ovld get_sub_group_id(void);
uint __ovld get_sub_group_local_id(void);
void __ovld __conv sub_group_barrier(cl_mem_fence_flags flags);
-#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
void __ovld __conv sub_group_barrier(cl_mem_fence_flags flags, memory_scope scope);
-#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0
+#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
int __ovld __conv sub_group_all(int predicate);
int __ovld __conv sub_group_any(int predicate);
@@ -15573,12 +15573,12 @@ uint2 __ovld __conv intel_sub_group_block_read2( read_only image2d_t image, in
uint4 __ovld __conv intel_sub_group_block_read4( read_only image2d_t image, int2 coord );
uint8 __ovld __conv intel_sub_group_block_read8( read_only image2d_t image, int2 coord );
-#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
uint __ovld __conv intel_sub_group_block_read(read_write image2d_t image, int2 coord);
uint2 __ovld __conv intel_sub_group_block_read2(read_write image2d_t image, int2 coord);
uint4 __ovld __conv intel_sub_group_block_read4(read_write image2d_t image, int2 coord);
uint8 __ovld __conv intel_sub_group_block_read8(read_write image2d_t image, int2 coord);
-#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
uint __ovld __conv intel_sub_group_block_read( const __global uint* p );
uint2 __ovld __conv intel_sub_group_block_read2( const __global uint* p );
@@ -15590,12 +15590,12 @@ void __ovld __conv intel_sub_group_block_write2(write_only image2d_t image, i
void __ovld __conv intel_sub_group_block_write4(write_only image2d_t image, int2 coord, uint4 data);
void __ovld __conv intel_sub_group_block_write8(write_only image2d_t image, int2 coord, uint8 data);
-#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
void __ovld __conv intel_sub_group_block_write(read_write image2d_t image, int2 coord, uint data);
void __ovld __conv intel_sub_group_block_write2(read_write image2d_t image, int2 coord, uint2 data);
void __ovld __conv intel_sub_group_block_write4(read_write image2d_t image, int2 coord, uint4 data);
void __ovld __conv intel_sub_group_block_write8(read_write image2d_t image, int2 coord, uint8 data);
-#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
void __ovld __conv intel_sub_group_block_write( __global uint* p, uint data );
void __ovld __conv intel_sub_group_block_write2( __global uint* p, uint2 data );
@@ -15713,12 +15713,12 @@ uint2 __ovld __conv intel_sub_group_block_read_ui2( read_only image2d_t ima
uint4 __ovld __conv intel_sub_group_block_read_ui4( read_only image2d_t image, int2 byte_coord );
uint8 __ovld __conv intel_sub_group_block_read_ui8( read_only image2d_t image, int2 byte_coord );
-#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
uint __ovld __conv intel_sub_group_block_read_ui( read_write image2d_t image, int2 byte_coord );
uint2 __ovld __conv intel_sub_group_block_read_ui2( read_write image2d_t image, int2 byte_coord );
uint4 __ovld __conv intel_sub_group_block_read_ui4( read_write image2d_t image, int2 byte_coord );
uint8 __ovld __conv intel_sub_group_block_read_ui8( read_write image2d_t image, int2 byte_coord );
-#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
uint __ovld __conv intel_sub_group_block_read_ui( const __global uint* p );
uint2 __ovld __conv intel_sub_group_block_read_ui2( const __global uint* p );
@@ -15730,12 +15730,12 @@ void __ovld __conv intel_sub_group_block_write_ui2( read_only image2d_t im
void __ovld __conv intel_sub_group_block_write_ui4( read_only image2d_t image, int2 byte_coord, uint4 data );
void __ovld __conv intel_sub_group_block_write_ui8( read_only image2d_t image, int2 byte_coord, uint8 data );
-#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
void __ovld __conv intel_sub_group_block_write_ui( read_write image2d_t image, int2 byte_coord, uint data );
void __ovld __conv intel_sub_group_block_write_ui2( read_write image2d_t image, int2 byte_coord, uint2 data );
void __ovld __conv intel_sub_group_block_write_ui4( read_write image2d_t image, int2 byte_coord, uint4 data );
void __ovld __conv intel_sub_group_block_write_ui8( read_write image2d_t image, int2 byte_coord, uint8 data );
-#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
void __ovld __conv intel_sub_group_block_write_ui( __global uint* p, uint data );
void __ovld __conv intel_sub_group_block_write_ui2( __global uint* p, uint2 data );
@@ -15747,12 +15747,12 @@ ushort2 __ovld __conv intel_sub_group_block_read_us2( read_only image2d_t im
ushort4 __ovld __conv intel_sub_group_block_read_us4( read_only image2d_t image, int2 coord );
ushort8 __ovld __conv intel_sub_group_block_read_us8( read_only image2d_t image, int2 coord );
-#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
ushort __ovld __conv intel_sub_group_block_read_us(read_write image2d_t image, int2 coord);
ushort2 __ovld __conv intel_sub_group_block_read_us2(read_write image2d_t image, int2 coord);
ushort4 __ovld __conv intel_sub_group_block_read_us4(read_write image2d_t image, int2 coord);
ushort8 __ovld __conv intel_sub_group_block_read_us8(read_write image2d_t image, int2 coord);
-#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
ushort __ovld __conv intel_sub_group_block_read_us( const __global ushort* p );
ushort2 __ovld __conv intel_sub_group_block_read_us2( const __global ushort* p );
@@ -15764,12 +15764,12 @@ void __ovld __conv intel_sub_group_block_write_us2(write_only image2d_t i
void __ovld __conv intel_sub_group_block_write_us4(write_only image2d_t image, int2 coord, ushort4 data);
void __ovld __conv intel_sub_group_block_write_us8(write_only image2d_t image, int2 coord, ushort8 data);
-#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
void __ovld __conv intel_sub_group_block_write_us(read_write image2d_t image, int2 coord, ushort data);
void __ovld __conv intel_sub_group_block_write_us2(read_write image2d_t image, int2 coord, ushort2 data);
void __ovld __conv intel_sub_group_block_write_us4(read_write image2d_t image, int2 coord, ushort4 data);
void __ovld __conv intel_sub_group_block_write_us8(read_write image2d_t image, int2 coord, ushort8 data);
-#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
+#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0)
void __ovld __conv intel_sub_group_block_write_us( __global ushort* p, ushort data );
void __ovld __conv intel_sub_group_block_write_us2( __global ushort* p, ushort2 data );
diff --git a/lib/Headers/ppc_wrappers/emmintrin.h b/lib/Headers/ppc_wrappers/emmintrin.h
index 617ce24acd3f..293276cc9be0 100644
--- a/lib/Headers/ppc_wrappers/emmintrin.h
+++ b/lib/Headers/ppc_wrappers/emmintrin.h
@@ -35,6 +35,8 @@
#ifndef EMMINTRIN_H_
#define EMMINTRIN_H_
+#if defined(__linux__) && defined(__ppc64__)
+
#include <altivec.h>
/* We need definitions from the SSE header files. */
@@ -2315,4 +2317,8 @@ _mm_castsi128_pd(__m128i __A)
return (__m128d) __A;
}
+#else
+#include_next <emmintrin.h>
+#endif /* defined(__linux__) && defined(__ppc64__) */
+
#endif /* EMMINTRIN_H_ */
diff --git a/lib/Headers/ppc_wrappers/mm_malloc.h b/lib/Headers/ppc_wrappers/mm_malloc.h
index d91d7865c893..24b14c8e07c0 100644
--- a/lib/Headers/ppc_wrappers/mm_malloc.h
+++ b/lib/Headers/ppc_wrappers/mm_malloc.h
@@ -10,6 +10,8 @@
#ifndef _MM_MALLOC_H_INCLUDED
#define _MM_MALLOC_H_INCLUDED
+#if defined(__linux__) && defined(__ppc64__)
+
#include <stdlib.h>
/* We can't depend on <stdlib.h> since the prototype of posix_memalign
@@ -41,4 +43,8 @@ _mm_free (void * ptr)
free (ptr);
}
+#else
+#include_next <mm_malloc.h>
+#endif
+
#endif /* _MM_MALLOC_H_INCLUDED */
diff --git a/lib/Headers/ppc_wrappers/mmintrin.h b/lib/Headers/ppc_wrappers/mmintrin.h
index b949653adf5a..c55c44726f00 100644
--- a/lib/Headers/ppc_wrappers/mmintrin.h
+++ b/lib/Headers/ppc_wrappers/mmintrin.h
@@ -35,6 +35,8 @@
#ifndef _MMINTRIN_H_INCLUDED
#define _MMINTRIN_H_INCLUDED
+#if defined(__linux__) && defined(__ppc64__)
+
#include <altivec.h>
/* The Intel API is flexible enough that we must allow aliasing with other
vector types, and their scalar components. */
@@ -1440,4 +1442,9 @@ extern __inline __m64
return (res.as_m64);
#endif
}
+
+#else
+#include_next <mmintrin.h>
+#endif /* defined(__linux__) && defined(__ppc64__) */
+
#endif /* _MMINTRIN_H_INCLUDED */
diff --git a/lib/Headers/ppc_wrappers/pmmintrin.h b/lib/Headers/ppc_wrappers/pmmintrin.h
new file mode 100644
index 000000000000..6d93383d5412
--- /dev/null
+++ b/lib/Headers/ppc_wrappers/pmmintrin.h
@@ -0,0 +1,150 @@
+/*===---- pmmintrin.h - Implementation of SSE3 intrinsics on PowerPC -------===
+ *
+ * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+ * See https://llvm.org/LICENSE.txt for license information.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+/* Implemented from the specification included in the Intel C++ Compiler
+ User Guide and Reference, version 9.0. */
+
+#ifndef NO_WARN_X86_INTRINSICS
+/* This header is distributed to simplify porting x86_64 code that
+ makes explicit use of Intel intrinsics to powerpc64le.
+ It is the user's responsibility to determine if the results are
+ acceptable and make additional changes as necessary.
+ Note that much code that uses Intel intrinsics can be rewritten in
+ standard C or GNU C extensions, which are more portable and better
+ optimized across multiple targets.
+
+ In the specific case of X86 SSE3 intrinsics, the PowerPC VMX/VSX ISA
+ is a good match for most SIMD operations. However the Horizontal
+ add/sub requires the data pairs be permuted into a separate
+ registers with vertical even/odd alignment for the operation.
+ And the addsub operation requires the sign of only the even numbered
+ elements be flipped (xored with -0.0).
+ For larger blocks of code using these intrinsic implementations,
+ the compiler be should be able to schedule instructions to avoid
+ additional latency.
+
+ In the specific case of the monitor and mwait instructions there are
+ no direct equivalent in the PowerISA at this time. So those
+ intrinsics are not implemented. */
+#error "Please read comment above. Use -DNO_WARN_X86_INTRINSICS to disable this warning."
+#endif
+
+#ifndef PMMINTRIN_H_
+#define PMMINTRIN_H_
+
+#if defined(__linux__) && defined(__ppc64__)
+
+/* We need definitions from the SSE2 and SSE header files*/
+#include <emmintrin.h>
+
+extern __inline __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_addsub_ps (__m128 __X, __m128 __Y)
+{
+ const __v4sf even_n0 = {-0.0, 0.0, -0.0, 0.0};
+ __v4sf even_neg_Y = vec_xor(__Y, even_n0);
+ return (__m128) vec_add (__X, even_neg_Y);
+}
+
+extern __inline __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_addsub_pd (__m128d __X, __m128d __Y)
+{
+ const __v2df even_n0 = {-0.0, 0.0};
+ __v2df even_neg_Y = vec_xor(__Y, even_n0);
+ return (__m128d) vec_add (__X, even_neg_Y);
+}
+
+extern __inline __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hadd_ps (__m128 __X, __m128 __Y)
+{
+ __vector unsigned char xform2 = {
+ 0x00, 0x01, 0x02, 0x03,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x10, 0x11, 0x12, 0x13,
+ 0x18, 0x19, 0x1A, 0x1B
+ };
+ __vector unsigned char xform1 = {
+ 0x04, 0x05, 0x06, 0x07,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x14, 0x15, 0x16, 0x17,
+ 0x1C, 0x1D, 0x1E, 0x1F
+ };
+ return (__m128) vec_add (vec_perm ((__v4sf) __X, (__v4sf) __Y, xform2),
+ vec_perm ((__v4sf) __X, (__v4sf) __Y, xform1));
+}
+
+extern __inline __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hsub_ps (__m128 __X, __m128 __Y)
+{
+ __vector unsigned char xform2 = {
+ 0x00, 0x01, 0x02, 0x03,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x10, 0x11, 0x12, 0x13,
+ 0x18, 0x19, 0x1A, 0x1B
+ };
+ __vector unsigned char xform1 = {
+ 0x04, 0x05, 0x06, 0x07,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x14, 0x15, 0x16, 0x17,
+ 0x1C, 0x1D, 0x1E, 0x1F
+ };
+ return (__m128) vec_sub (vec_perm ((__v4sf) __X, (__v4sf) __Y, xform2),
+ vec_perm ((__v4sf) __X, (__v4sf) __Y, xform1));
+}
+
+extern __inline __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hadd_pd (__m128d __X, __m128d __Y)
+{
+ return (__m128d) vec_add (vec_mergeh ((__v2df) __X, (__v2df)__Y),
+ vec_mergel ((__v2df) __X, (__v2df)__Y));
+}
+
+extern __inline __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hsub_pd (__m128d __X, __m128d __Y)
+{
+ return (__m128d) vec_sub (vec_mergeh ((__v2df) __X, (__v2df)__Y),
+ vec_mergel ((__v2df) __X, (__v2df)__Y));
+}
+
+extern __inline __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_movehdup_ps (__m128 __X)
+{
+ return (__m128)vec_mergeo ((__v4su)__X, (__v4su)__X);
+}
+
+extern __inline __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_moveldup_ps (__m128 __X)
+{
+ return (__m128)vec_mergee ((__v4su)__X, (__v4su)__X);
+}
+
+extern __inline __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_loaddup_pd (double const *__P)
+{
+ return (__m128d) vec_splats (*__P);
+}
+
+extern __inline __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_movedup_pd (__m128d __X)
+{
+ return _mm_shuffle_pd (__X, __X, _MM_SHUFFLE2 (0,0));
+}
+
+extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_lddqu_si128 (__m128i const *__P)
+{
+ return (__m128i) (vec_vsx_ld(0, (signed int const *)__P));
+}
+
+/* POWER8 / POWER9 have no equivalent for _mm_monitor nor _mm_wait. */
+
+#else
+#include_next <pmmintrin.h>
+#endif /* defined(__linux__) && defined(__ppc64__) */
+
+#endif /* PMMINTRIN_H_ */
diff --git a/lib/Headers/ppc_wrappers/smmintrin.h b/lib/Headers/ppc_wrappers/smmintrin.h
new file mode 100644
index 000000000000..56ef6ba76b06
--- /dev/null
+++ b/lib/Headers/ppc_wrappers/smmintrin.h
@@ -0,0 +1,85 @@
+/*===---- smmintrin.h - Implementation of SSE4 intrinsics on PowerPC -------===
+ *
+ * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+ * See https://llvm.org/LICENSE.txt for license information.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+/* Implemented from the specification included in the Intel C++ Compiler
+ User Guide and Reference, version 9.0.
+
+ NOTE: This is NOT a complete implementation of the SSE4 intrinsics! */
+
+#ifndef NO_WARN_X86_INTRINSICS
+/* This header is distributed to simplify porting x86_64 code that
+ makes explicit use of Intel intrinsics to powerp64/powerpc64le.
+
+ It is the user's responsibility to determine if the results are
+ acceptable and make additional changes as necessary.
+
+ Note that much code that uses Intel intrinsics can be rewritten in
+ standard C or GNU C extensions, which are more portable and better
+ optimized across multiple targets. */
+#error \
+ "Please read comment above. Use -DNO_WARN_X86_INTRINSICS to disable this error."
+#endif
+
+#ifndef SMMINTRIN_H_
+#define SMMINTRIN_H_
+
+#if defined(__linux__) && defined(__ppc64__)
+
+#include <altivec.h>
+#include <emmintrin.h>
+
+extern __inline int
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ _mm_extract_epi8(__m128i __X, const int __N) {
+ return (unsigned char)((__v16qi)__X)[__N & 15];
+}
+
+extern __inline int
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ _mm_extract_epi32(__m128i __X, const int __N) {
+ return ((__v4si)__X)[__N & 3];
+}
+
+extern __inline int
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ _mm_extract_epi64(__m128i __X, const int __N) {
+ return ((__v2di)__X)[__N & 1];
+}
+
+extern __inline int
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ _mm_extract_ps(__m128 __X, const int __N) {
+ return ((__v4si)__X)[__N & 3];
+}
+
+extern __inline __m128i
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ _mm_blend_epi16(__m128i __A, __m128i __B, const int __imm8) {
+ __v16qi __charmask = vec_splats((signed char)__imm8);
+ __charmask = vec_gb(__charmask);
+ __v8hu __shortmask = (__v8hu)vec_unpackh(__charmask);
+#ifdef __BIG_ENDIAN__
+ __shortmask = vec_reve(__shortmask);
+#endif
+ return (__m128i)vec_sel((__v8hu)__A, (__v8hu)__B, __shortmask);
+}
+
+extern __inline __m128i
+ __attribute__((__gnu_inline__, __always_inline__, __artificial__))
+ _mm_blendv_epi8(__m128i __A, __m128i __B, __m128i __mask) {
+ const __v16qu __seven = vec_splats((unsigned char)0x07);
+ __v16qu __lmask = vec_sra((__v16qu)__mask, __seven);
+ return (__m128i)vec_sel((__v16qu)__A, (__v16qu)__B, __lmask);
+}
+
+#else
+#include_next <smmintrin.h>
+#endif /* defined(__linux__) && defined(__ppc64__) */
+
+#endif /* _SMMINTRIN_H_ */
diff --git a/lib/Headers/ppc_wrappers/tmmintrin.h b/lib/Headers/ppc_wrappers/tmmintrin.h
new file mode 100644
index 000000000000..b5a935d5e47e
--- /dev/null
+++ b/lib/Headers/ppc_wrappers/tmmintrin.h
@@ -0,0 +1,495 @@
+/*===---- tmmintrin.h - Implementation of SSSE3 intrinsics on PowerPC ------===
+ *
+ * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+ * See https://llvm.org/LICENSE.txt for license information.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+/* Implemented from the specification included in the Intel C++ Compiler
+ User Guide and Reference, version 9.0. */
+
+#ifndef NO_WARN_X86_INTRINSICS
+/* This header is distributed to simplify porting x86_64 code that
+ makes explicit use of Intel intrinsics to powerpc64le.
+
+ It is the user's responsibility to determine if the results are
+ acceptable and make additional changes as necessary.
+
+ Note that much code that uses Intel intrinsics can be rewritten in
+ standard C or GNU C extensions, which are more portable and better
+ optimized across multiple targets. */
+#endif
+
+#ifndef TMMINTRIN_H_
+#define TMMINTRIN_H_
+
+#if defined(__linux__) && defined(__ppc64__)
+
+#include <altivec.h>
+
+/* We need definitions from the SSE header files. */
+#include <pmmintrin.h>
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_abs_epi16 (__m128i __A)
+{
+ return (__m128i) vec_abs ((__v8hi) __A);
+}
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_abs_epi32 (__m128i __A)
+{
+ return (__m128i) vec_abs ((__v4si) __A);
+}
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_abs_epi8 (__m128i __A)
+{
+ return (__m128i) vec_abs ((__v16qi) __A);
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_abs_pi16 (__m64 __A)
+{
+ __v8hi __B = (__v8hi) (__v2du) { __A, __A };
+ return (__m64) ((__v2du) vec_abs (__B))[0];
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_abs_pi32 (__m64 __A)
+{
+ __v4si __B = (__v4si) (__v2du) { __A, __A };
+ return (__m64) ((__v2du) vec_abs (__B))[0];
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_abs_pi8 (__m64 __A)
+{
+ __v16qi __B = (__v16qi) (__v2du) { __A, __A };
+ return (__m64) ((__v2du) vec_abs (__B))[0];
+}
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_alignr_epi8 (__m128i __A, __m128i __B, const unsigned int __count)
+{
+ if (__builtin_constant_p (__count) && __count < 16)
+ {
+#ifdef __LITTLE_ENDIAN__
+ __A = (__m128i) vec_reve ((__v16qu) __A);
+ __B = (__m128i) vec_reve ((__v16qu) __B);
+#endif
+ __A = (__m128i) vec_sld ((__v16qu) __B, (__v16qu) __A, __count);
+#ifdef __LITTLE_ENDIAN__
+ __A = (__m128i) vec_reve ((__v16qu) __A);
+#endif
+ return __A;
+ }
+
+ if (__count == 0)
+ return __B;
+
+ if (__count >= 16)
+ {
+ if (__count >= 32)
+ {
+ const __v16qu zero = { 0 };
+ return (__m128i) zero;
+ }
+ else
+ {
+ const __v16qu __shift =
+ vec_splats ((unsigned char) ((__count - 16) * 8));
+#ifdef __LITTLE_ENDIAN__
+ return (__m128i) vec_sro ((__v16qu) __A, __shift);
+#else
+ return (__m128i) vec_slo ((__v16qu) __A, __shift);
+#endif
+ }
+ }
+ else
+ {
+ const __v16qu __shiftA =
+ vec_splats ((unsigned char) ((16 - __count) * 8));
+ const __v16qu __shiftB = vec_splats ((unsigned char) (__count * 8));
+#ifdef __LITTLE_ENDIAN__
+ __A = (__m128i) vec_slo ((__v16qu) __A, __shiftA);
+ __B = (__m128i) vec_sro ((__v16qu) __B, __shiftB);
+#else
+ __A = (__m128i) vec_sro ((__v16qu) __A, __shiftA);
+ __B = (__m128i) vec_slo ((__v16qu) __B, __shiftB);
+#endif
+ return (__m128i) vec_or ((__v16qu) __A, (__v16qu) __B);
+ }
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_alignr_pi8 (__m64 __A, __m64 __B, unsigned int __count)
+{
+ if (__count < 16)
+ {
+ __v2du __C = { __B, __A };
+#ifdef __LITTLE_ENDIAN__
+ const __v4su __shift = { __count << 3, 0, 0, 0 };
+ __C = (__v2du) vec_sro ((__v16qu) __C, (__v16qu) __shift);
+#else
+ const __v4su __shift = { 0, 0, 0, __count << 3 };
+ __C = (__v2du) vec_slo ((__v16qu) __C, (__v16qu) __shift);
+#endif
+ return (__m64) __C[0];
+ }
+ else
+ {
+ const __m64 __zero = { 0 };
+ return __zero;
+ }
+}
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hadd_epi16 (__m128i __A, __m128i __B)
+{
+ const __v16qu __P =
+ { 0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29 };
+ const __v16qu __Q =
+ { 2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31 };
+ __v8hi __C = vec_perm ((__v8hi) __A, (__v8hi) __B, __P);
+ __v8hi __D = vec_perm ((__v8hi) __A, (__v8hi) __B, __Q);
+ return (__m128i) vec_add (__C, __D);
+}
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hadd_epi32 (__m128i __A, __m128i __B)
+{
+ const __v16qu __P =
+ { 0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27 };
+ const __v16qu __Q =
+ { 4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31 };
+ __v4si __C = vec_perm ((__v4si) __A, (__v4si) __B, __P);
+ __v4si __D = vec_perm ((__v4si) __A, (__v4si) __B, __Q);
+ return (__m128i) vec_add (__C, __D);
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hadd_pi16 (__m64 __A, __m64 __B)
+{
+ __v8hi __C = (__v8hi) (__v2du) { __A, __B };
+ const __v16qu __P =
+ { 0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13 };
+ const __v16qu __Q =
+ { 2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15 };
+ __v8hi __D = vec_perm (__C, __C, __Q);
+ __C = vec_perm (__C, __C, __P);
+ __C = vec_add (__C, __D);
+ return (__m64) ((__v2du) __C)[1];
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hadd_pi32 (__m64 __A, __m64 __B)
+{
+ __v4si __C = (__v4si) (__v2du) { __A, __B };
+ const __v16qu __P =
+ { 0, 1, 2, 3, 8, 9, 10, 11, 0, 1, 2, 3, 8, 9, 10, 11 };
+ const __v16qu __Q =
+ { 4, 5, 6, 7, 12, 13, 14, 15, 4, 5, 6, 7, 12, 13, 14, 15 };
+ __v4si __D = vec_perm (__C, __C, __Q);
+ __C = vec_perm (__C, __C, __P);
+ __C = vec_add (__C, __D);
+ return (__m64) ((__v2du) __C)[1];
+}
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hadds_epi16 (__m128i __A, __m128i __B)
+{
+ __v4si __C = { 0 }, __D = { 0 };
+ __C = vec_sum4s ((__v8hi) __A, __C);
+ __D = vec_sum4s ((__v8hi) __B, __D);
+ __C = (__v4si) vec_packs (__C, __D);
+ return (__m128i) __C;
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hadds_pi16 (__m64 __A, __m64 __B)
+{
+ const __v4si __zero = { 0 };
+ __v8hi __C = (__v8hi) (__v2du) { __A, __B };
+ __v4si __D = vec_sum4s (__C, __zero);
+ __C = vec_packs (__D, __D);
+ return (__m64) ((__v2du) __C)[1];
+}
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hsub_epi16 (__m128i __A, __m128i __B)
+{
+ const __v16qu __P =
+ { 0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29 };
+ const __v16qu __Q =
+ { 2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31 };
+ __v8hi __C = vec_perm ((__v8hi) __A, (__v8hi) __B, __P);
+ __v8hi __D = vec_perm ((__v8hi) __A, (__v8hi) __B, __Q);
+ return (__m128i) vec_sub (__C, __D);
+}
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hsub_epi32 (__m128i __A, __m128i __B)
+{
+ const __v16qu __P =
+ { 0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27 };
+ const __v16qu __Q =
+ { 4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31 };
+ __v4si __C = vec_perm ((__v4si) __A, (__v4si) __B, __P);
+ __v4si __D = vec_perm ((__v4si) __A, (__v4si) __B, __Q);
+ return (__m128i) vec_sub (__C, __D);
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hsub_pi16 (__m64 __A, __m64 __B)
+{
+ const __v16qu __P =
+ { 0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13 };
+ const __v16qu __Q =
+ { 2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15 };
+ __v8hi __C = (__v8hi) (__v2du) { __A, __B };
+ __v8hi __D = vec_perm (__C, __C, __Q);
+ __C = vec_perm (__C, __C, __P);
+ __C = vec_sub (__C, __D);
+ return (__m64) ((__v2du) __C)[1];
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hsub_pi32 (__m64 __A, __m64 __B)
+{
+ const __v16qu __P =
+ { 0, 1, 2, 3, 8, 9, 10, 11, 0, 1, 2, 3, 8, 9, 10, 11 };
+ const __v16qu __Q =
+ { 4, 5, 6, 7, 12, 13, 14, 15, 4, 5, 6, 7, 12, 13, 14, 15 };
+ __v4si __C = (__v4si) (__v2du) { __A, __B };
+ __v4si __D = vec_perm (__C, __C, __Q);
+ __C = vec_perm (__C, __C, __P);
+ __C = vec_sub (__C, __D);
+ return (__m64) ((__v2du) __C)[1];
+}
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hsubs_epi16 (__m128i __A, __m128i __B)
+{
+ const __v16qu __P =
+ { 0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29 };
+ const __v16qu __Q =
+ { 2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31 };
+ __v8hi __C = vec_perm ((__v8hi) __A, (__v8hi) __B, __P);
+ __v8hi __D = vec_perm ((__v8hi) __A, (__v8hi) __B, __Q);
+ return (__m128i) vec_subs (__C, __D);
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_hsubs_pi16 (__m64 __A, __m64 __B)
+{
+ const __v16qu __P =
+ { 0, 1, 4, 5, 8, 9, 12, 13, 0, 1, 4, 5, 8, 9, 12, 13 };
+ const __v16qu __Q =
+ { 2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15 };
+ __v8hi __C = (__v8hi) (__v2du) { __A, __B };
+ __v8hi __D = vec_perm (__C, __C, __P);
+ __v8hi __E = vec_perm (__C, __C, __Q);
+ __C = vec_subs (__D, __E);
+ return (__m64) ((__v2du) __C)[1];
+}
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_shuffle_epi8 (__m128i __A, __m128i __B)
+{
+ const __v16qi __zero = { 0 };
+ __vector __bool char __select = vec_cmplt ((__v16qi) __B, __zero);
+ __v16qi __C = vec_perm ((__v16qi) __A, (__v16qi) __A, (__v16qu) __B);
+ return (__m128i) vec_sel (__C, __zero, __select);
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_shuffle_pi8 (__m64 __A, __m64 __B)
+{
+ const __v16qi __zero = { 0 };
+ __v16qi __C = (__v16qi) (__v2du) { __A, __A };
+ __v16qi __D = (__v16qi) (__v2du) { __B, __B };
+ __vector __bool char __select = vec_cmplt ((__v16qi) __D, __zero);
+ __C = vec_perm ((__v16qi) __C, (__v16qi) __C, (__v16qu) __D);
+ __C = vec_sel (__C, __zero, __select);
+ return (__m64) ((__v2du) (__C))[0];
+}
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_sign_epi8 (__m128i __A, __m128i __B)
+{
+ const __v16qi __zero = { 0 };
+ __v16qi __selectneg = (__v16qi) vec_cmplt ((__v16qi) __B, __zero);
+ __v16qi __selectpos =
+ (__v16qi) vec_neg ((__v16qi) vec_cmpgt ((__v16qi) __B, __zero));
+ __v16qi __conv = vec_add (__selectneg, __selectpos);
+ return (__m128i) vec_mul ((__v16qi) __A, (__v16qi) __conv);
+}
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_sign_epi16 (__m128i __A, __m128i __B)
+{
+ const __v8hi __zero = { 0 };
+ __v8hi __selectneg = (__v8hi) vec_cmplt ((__v8hi) __B, __zero);
+ __v8hi __selectpos =
+ (__v8hi) vec_neg ((__v8hi) vec_cmpgt ((__v8hi) __B, __zero));
+ __v8hi __conv = vec_add (__selectneg, __selectpos);
+ return (__m128i) vec_mul ((__v8hi) __A, (__v8hi) __conv);
+}
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_sign_epi32 (__m128i __A, __m128i __B)
+{
+ const __v4si __zero = { 0 };
+ __v4si __selectneg = (__v4si) vec_cmplt ((__v4si) __B, __zero);
+ __v4si __selectpos =
+ (__v4si) vec_neg ((__v4si) vec_cmpgt ((__v4si) __B, __zero));
+ __v4si __conv = vec_add (__selectneg, __selectpos);
+ return (__m128i) vec_mul ((__v4si) __A, (__v4si) __conv);
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_sign_pi8 (__m64 __A, __m64 __B)
+{
+ const __v16qi __zero = { 0 };
+ __v16qi __C = (__v16qi) (__v2du) { __A, __A };
+ __v16qi __D = (__v16qi) (__v2du) { __B, __B };
+ __C = (__v16qi) _mm_sign_epi8 ((__m128i) __C, (__m128i) __D);
+ return (__m64) ((__v2du) (__C))[0];
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_sign_pi16 (__m64 __A, __m64 __B)
+{
+ const __v8hi __zero = { 0 };
+ __v8hi __C = (__v8hi) (__v2du) { __A, __A };
+ __v8hi __D = (__v8hi) (__v2du) { __B, __B };
+ __C = (__v8hi) _mm_sign_epi16 ((__m128i) __C, (__m128i) __D);
+ return (__m64) ((__v2du) (__C))[0];
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_sign_pi32 (__m64 __A, __m64 __B)
+{
+ const __v4si __zero = { 0 };
+ __v4si __C = (__v4si) (__v2du) { __A, __A };
+ __v4si __D = (__v4si) (__v2du) { __B, __B };
+ __C = (__v4si) _mm_sign_epi32 ((__m128i) __C, (__m128i) __D);
+ return (__m64) ((__v2du) (__C))[0];
+}
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_maddubs_epi16 (__m128i __A, __m128i __B)
+{
+ __v8hi __unsigned = vec_splats ((signed short) 0x00ff);
+ __v8hi __C = vec_and (vec_unpackh ((__v16qi) __A), __unsigned);
+ __v8hi __D = vec_and (vec_unpackl ((__v16qi) __A), __unsigned);
+ __v8hi __E = vec_unpackh ((__v16qi) __B);
+ __v8hi __F = vec_unpackl ((__v16qi) __B);
+ __C = vec_mul (__C, __E);
+ __D = vec_mul (__D, __F);
+ const __v16qu __odds =
+ { 0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29 };
+ const __v16qu __evens =
+ { 2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31 };
+ __E = vec_perm (__C, __D, __odds);
+ __F = vec_perm (__C, __D, __evens);
+ return (__m128i) vec_adds (__E, __F);
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_maddubs_pi16 (__m64 __A, __m64 __B)
+{
+ __v8hi __C = (__v8hi) (__v2du) { __A, __A };
+ __C = vec_unpackl ((__v16qi) __C);
+ const __v8hi __unsigned = vec_splats ((signed short) 0x00ff);
+ __C = vec_and (__C, __unsigned);
+ __v8hi __D = (__v8hi) (__v2du) { __B, __B };
+ __D = vec_unpackl ((__v16qi) __D);
+ __D = vec_mul (__C, __D);
+ const __v16qu __odds =
+ { 0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29 };
+ const __v16qu __evens =
+ { 2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31 };
+ __C = vec_perm (__D, __D, __odds);
+ __D = vec_perm (__D, __D, __evens);
+ __C = vec_adds (__C, __D);
+ return (__m64) ((__v2du) (__C))[0];
+}
+
+extern __inline __m128i
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_mulhrs_epi16 (__m128i __A, __m128i __B)
+{
+ __v4si __C = vec_unpackh ((__v8hi) __A);
+ __v4si __D = vec_unpackh ((__v8hi) __B);
+ __C = vec_mul (__C, __D);
+ __D = vec_unpackl ((__v8hi) __A);
+ __v4si __E = vec_unpackl ((__v8hi) __B);
+ __D = vec_mul (__D, __E);
+ const __v4su __shift = vec_splats ((unsigned int) 14);
+ __C = vec_sr (__C, __shift);
+ __D = vec_sr (__D, __shift);
+ const __v4si __ones = vec_splats ((signed int) 1);
+ __C = vec_add (__C, __ones);
+ __C = vec_sr (__C, (__v4su) __ones);
+ __D = vec_add (__D, __ones);
+ __D = vec_sr (__D, (__v4su) __ones);
+ return (__m128i) vec_pack (__C, __D);
+}
+
+extern __inline __m64
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_mm_mulhrs_pi16 (__m64 __A, __m64 __B)
+{
+ __v4si __C = (__v4si) (__v2du) { __A, __A };
+ __C = vec_unpackh ((__v8hi) __C);
+ __v4si __D = (__v4si) (__v2du) { __B, __B };
+ __D = vec_unpackh ((__v8hi) __D);
+ __C = vec_mul (__C, __D);
+ const __v4su __shift = vec_splats ((unsigned int) 14);
+ __C = vec_sr (__C, __shift);
+ const __v4si __ones = vec_splats ((signed int) 1);
+ __C = vec_add (__C, __ones);
+ __C = vec_sr (__C, (__v4su) __ones);
+ __v8hi __E = vec_pack (__C, __D);
+ return (__m64) ((__v2du) (__E))[0];
+}
+
+#else
+#include_next <tmmintrin.h>
+#endif /* defined(__linux__) && defined(__ppc64__) */
+
+#endif /* TMMINTRIN_H_ */
diff --git a/lib/Headers/ppc_wrappers/xmmintrin.h b/lib/Headers/ppc_wrappers/xmmintrin.h
index 1b322b66519a..0f429fa04081 100644
--- a/lib/Headers/ppc_wrappers/xmmintrin.h
+++ b/lib/Headers/ppc_wrappers/xmmintrin.h
@@ -34,6 +34,8 @@
#ifndef _XMMINTRIN_H_INCLUDED
#define _XMMINTRIN_H_INCLUDED
+#if defined(__linux__) && defined(__ppc64__)
+
/* Define four value permute mask */
#define _MM_SHUFFLE(w,x,y,z) (((w) << 6) | ((x) << 4) | ((y) << 2) | (z))
@@ -1835,4 +1837,8 @@ do { \
/* For backward source compatibility. */
//# include <emmintrin.h>
+#else
+#include_next <xmmintrin.h>
+#endif /* defined(__linux__) && defined(__ppc64__) */
+
#endif /* _XMMINTRIN_H_INCLUDED */
diff --git a/lib/Index/CodegenNameGenerator.cpp b/lib/Index/CodegenNameGenerator.cpp
deleted file mode 100644
index 56d3d0603486..000000000000
--- a/lib/Index/CodegenNameGenerator.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-//===- CodegenNameGenerator.cpp - Codegen name generation -----------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Determines the name that the symbol will get for code generation.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Index/CodegenNameGenerator.h"
-#include "clang/AST/ASTContext.h"
-
-using namespace clang;
-using namespace clang::index;
-
-CodegenNameGenerator::CodegenNameGenerator(ASTContext &Ctx)
- : Impl(new ASTNameGenerator(Ctx)) {
-}
-
-CodegenNameGenerator::~CodegenNameGenerator() {
-}
-
-bool CodegenNameGenerator::writeName(const Decl *D, raw_ostream &OS) {
- return Impl->writeName(D, OS);
-}
-
-std::string CodegenNameGenerator::getName(const Decl *D) {
- return Impl->getName(D);
-}
-
-std::vector<std::string> CodegenNameGenerator::getAllManglings(const Decl *D) {
- return Impl->getAllManglings(D);
-}
diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp
index 064f3ae32f9e..5165567ff75e 100644
--- a/lib/Index/IndexSymbol.cpp
+++ b/lib/Index/IndexSymbol.cpp
@@ -513,7 +513,7 @@ StringRef index::getSymbolKindString(SymbolKind K) {
case SymbolKind::StaticProperty: return "static-property";
case SymbolKind::Constructor: return "constructor";
case SymbolKind::Destructor: return "destructor";
- case SymbolKind::ConversionFunction: return "coversion-func";
+ case SymbolKind::ConversionFunction: return "conversion-func";
case SymbolKind::Parameter: return "param";
case SymbolKind::Using: return "using";
}
diff --git a/lib/Index/IndexingAction.cpp b/lib/Index/IndexingAction.cpp
index 5a805c4abcd6..6d6133e89d86 100644
--- a/lib/Index/IndexingAction.cpp
+++ b/lib/Index/IndexingAction.cpp
@@ -21,62 +21,9 @@
using namespace clang;
using namespace clang::index;
-bool IndexDataConsumer::handleDeclOccurence(const Decl *D, SymbolRoleSet Roles,
- ArrayRef<SymbolRelation> Relations,
- SourceLocation Loc,
- ASTNodeInfo ASTNode) {
- return true;
-}
-
-bool IndexDataConsumer::handleMacroOccurence(const IdentifierInfo *Name,
- const MacroInfo *MI,
- SymbolRoleSet Roles,
- SourceLocation Loc) {
- return true;
-}
-
-bool IndexDataConsumer::handleModuleOccurence(const ImportDecl *ImportD,
- const Module *Mod,
- SymbolRoleSet Roles,
- SourceLocation Loc) {
- return true;
-}
-
namespace {
-class IndexASTConsumer : public ASTConsumer {
- std::shared_ptr<Preprocessor> PP;
- std::shared_ptr<IndexingContext> IndexCtx;
-
-public:
- IndexASTConsumer(std::shared_ptr<Preprocessor> PP,
- std::shared_ptr<IndexingContext> IndexCtx)
- : PP(std::move(PP)), IndexCtx(std::move(IndexCtx)) {}
-
-protected:
- void Initialize(ASTContext &Context) override {
- IndexCtx->setASTContext(Context);
- IndexCtx->getDataConsumer().initialize(Context);
- IndexCtx->getDataConsumer().setPreprocessor(PP);
- }
-
- bool HandleTopLevelDecl(DeclGroupRef DG) override {
- return IndexCtx->indexDeclGroupRef(DG);
- }
-
- void HandleInterestingDecl(DeclGroupRef DG) override {
- // Ignore deserialized decls.
- }
-
- void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override {
- IndexCtx->indexDeclGroupRef(DG);
- }
-
- void HandleTranslationUnit(ASTContext &Ctx) override {
- }
-};
-
-class IndexPPCallbacks : public PPCallbacks {
+class IndexPPCallbacks final : public PPCallbacks {
std::shared_ptr<IndexingContext> IndexCtx;
public:
@@ -106,104 +53,89 @@ public:
}
};
-class IndexActionBase {
-protected:
+class IndexASTConsumer final : public ASTConsumer {
std::shared_ptr<IndexDataConsumer> DataConsumer;
std::shared_ptr<IndexingContext> IndexCtx;
+ std::shared_ptr<Preprocessor> PP;
+ std::function<bool(const Decl *)> ShouldSkipFunctionBody;
- IndexActionBase(std::shared_ptr<IndexDataConsumer> dataConsumer,
- IndexingOptions Opts)
- : DataConsumer(std::move(dataConsumer)),
- IndexCtx(new IndexingContext(Opts, *DataConsumer)) {}
-
- std::unique_ptr<IndexASTConsumer>
- createIndexASTConsumer(CompilerInstance &CI) {
- return llvm::make_unique<IndexASTConsumer>(CI.getPreprocessorPtr(),
- IndexCtx);
+public:
+ IndexASTConsumer(std::shared_ptr<IndexDataConsumer> DataConsumer,
+ const IndexingOptions &Opts,
+ std::shared_ptr<Preprocessor> PP,
+ std::function<bool(const Decl *)> ShouldSkipFunctionBody)
+ : DataConsumer(std::move(DataConsumer)),
+ IndexCtx(new IndexingContext(Opts, *this->DataConsumer)),
+ PP(std::move(PP)),
+ ShouldSkipFunctionBody(std::move(ShouldSkipFunctionBody)) {
+ assert(this->DataConsumer != nullptr);
+ assert(this->PP != nullptr);
}
- std::unique_ptr<PPCallbacks> createIndexPPCallbacks() {
- return llvm::make_unique<IndexPPCallbacks>(IndexCtx);
+protected:
+ void Initialize(ASTContext &Context) override {
+ IndexCtx->setASTContext(Context);
+ IndexCtx->getDataConsumer().initialize(Context);
+ IndexCtx->getDataConsumer().setPreprocessor(PP);
+ PP->addPPCallbacks(std::make_unique<IndexPPCallbacks>(IndexCtx));
}
- void finish() {
- DataConsumer->finish();
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ return IndexCtx->indexDeclGroupRef(DG);
}
-};
-class IndexAction : public ASTFrontendAction, IndexActionBase {
-public:
- IndexAction(std::shared_ptr<IndexDataConsumer> DataConsumer,
- IndexingOptions Opts)
- : IndexActionBase(std::move(DataConsumer), Opts) {}
+ void HandleInterestingDecl(DeclGroupRef DG) override {
+ // Ignore deserialized decls.
+ }
-protected:
- std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
- StringRef InFile) override {
- return createIndexASTConsumer(CI);
+ void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override {
+ IndexCtx->indexDeclGroupRef(DG);
}
- bool BeginSourceFileAction(clang::CompilerInstance &CI) override {
- CI.getPreprocessor().addPPCallbacks(createIndexPPCallbacks());
- return true;
+ void HandleTranslationUnit(ASTContext &Ctx) override {
+ DataConsumer->finish();
}
- void EndSourceFileAction() override {
- FrontendAction::EndSourceFileAction();
- finish();
+ bool shouldSkipFunctionBody(Decl *D) override {
+ return ShouldSkipFunctionBody(D);
}
};
-class WrappingIndexAction : public WrapperFrontendAction, IndexActionBase {
- bool IndexActionFailed = false;
+class IndexAction final : public ASTFrontendAction {
+ std::shared_ptr<IndexDataConsumer> DataConsumer;
+ IndexingOptions Opts;
public:
- WrappingIndexAction(std::unique_ptr<FrontendAction> WrappedAction,
- std::shared_ptr<IndexDataConsumer> DataConsumer,
- IndexingOptions Opts)
- : WrapperFrontendAction(std::move(WrappedAction)),
- IndexActionBase(std::move(DataConsumer), Opts) {}
+ IndexAction(std::shared_ptr<IndexDataConsumer> DataConsumer,
+ const IndexingOptions &Opts)
+ : DataConsumer(std::move(DataConsumer)), Opts(Opts) {
+ assert(this->DataConsumer != nullptr);
+ }
protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override {
- auto OtherConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
- if (!OtherConsumer) {
- IndexActionFailed = true;
- return nullptr;
- }
-
- std::vector<std::unique_ptr<ASTConsumer>> Consumers;
- Consumers.push_back(std::move(OtherConsumer));
- Consumers.push_back(createIndexASTConsumer(CI));
- return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
- }
-
- bool BeginSourceFileAction(clang::CompilerInstance &CI) override {
- WrapperFrontendAction::BeginSourceFileAction(CI);
- CI.getPreprocessor().addPPCallbacks(createIndexPPCallbacks());
- return true;
- }
-
- void EndSourceFileAction() override {
- // Invoke wrapped action's method.
- WrapperFrontendAction::EndSourceFileAction();
- if (!IndexActionFailed)
- finish();
+ return std::make_unique<IndexASTConsumer>(
+ DataConsumer, Opts, CI.getPreprocessorPtr(),
+ /*ShouldSkipFunctionBody=*/[](const Decl *) { return false; });
}
};
} // anonymous namespace
+std::unique_ptr<ASTConsumer> index::createIndexingASTConsumer(
+ std::shared_ptr<IndexDataConsumer> DataConsumer,
+ const IndexingOptions &Opts, std::shared_ptr<Preprocessor> PP,
+ std::function<bool(const Decl *)> ShouldSkipFunctionBody) {
+ return std::make_unique<IndexASTConsumer>(DataConsumer, Opts, PP,
+ ShouldSkipFunctionBody);
+}
+
std::unique_ptr<FrontendAction>
index::createIndexingAction(std::shared_ptr<IndexDataConsumer> DataConsumer,
- IndexingOptions Opts,
- std::unique_ptr<FrontendAction> WrappedAction) {
- if (WrappedAction)
- return llvm::make_unique<WrappingIndexAction>(std::move(WrappedAction),
- std::move(DataConsumer),
- Opts);
- return llvm::make_unique<IndexAction>(std::move(DataConsumer), Opts);
+ const IndexingOptions &Opts) {
+ assert(DataConsumer != nullptr);
+ return std::make_unique<IndexAction>(std::move(DataConsumer), Opts);
}
static bool topLevelDeclVisitor(void *context, const Decl *D) {
@@ -257,7 +189,7 @@ void index::indexTopLevelDecls(ASTContext &Ctx, Preprocessor &PP,
std::unique_ptr<PPCallbacks>
index::indexMacrosCallback(IndexDataConsumer &Consumer, IndexingOptions Opts) {
- return llvm::make_unique<IndexPPCallbacks>(
+ return std::make_unique<IndexPPCallbacks>(
std::make_shared<IndexingContext>(Opts, Consumer));
}
diff --git a/lib/Index/USRGeneration.cpp b/lib/Index/USRGeneration.cpp
index 228651de928e..f4316fe7d067 100644
--- a/lib/Index/USRGeneration.cpp
+++ b/lib/Index/USRGeneration.cpp
@@ -724,6 +724,9 @@ void USRGenerator::VisitType(QualType T) {
case BuiltinType::OCLQueue:
case BuiltinType::OCLReserveID:
case BuiltinType::OCLSampler:
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
case BuiltinType::ShortAccum:
case BuiltinType::Accum:
case BuiltinType::LongAccum:
diff --git a/lib/Lex/DependencyDirectivesSourceMinimizer.cpp b/lib/Lex/DependencyDirectivesSourceMinimizer.cpp
index cfc37c5d3c62..f063ed711c44 100644
--- a/lib/Lex/DependencyDirectivesSourceMinimizer.cpp
+++ b/lib/Lex/DependencyDirectivesSourceMinimizer.cpp
@@ -59,6 +59,7 @@ private:
LLVM_NODISCARD bool minimizeImpl(const char *First, const char *const End);
LLVM_NODISCARD bool lexPPLine(const char *&First, const char *const End);
LLVM_NODISCARD bool lexAt(const char *&First, const char *const End);
+ LLVM_NODISCARD bool lexModule(const char *&First, const char *const End);
LLVM_NODISCARD bool lexDefine(const char *&First, const char *const End);
LLVM_NODISCARD bool lexPragma(const char *&First, const char *const End);
LLVM_NODISCARD bool lexEndif(const char *&First, const char *const End);
@@ -184,26 +185,58 @@ static void skipRawString(const char *&First, const char *const End) {
}
}
+// Returns the length of EOL, either 0 (no end-of-line), 1 (\n) or 2 (\r\n)
+static unsigned isEOL(const char *First, const char *const End) {
+ if (First == End)
+ return 0;
+ if (End - First > 1 && isVerticalWhitespace(First[0]) &&
+ isVerticalWhitespace(First[1]) && First[0] != First[1])
+ return 2;
+ return !!isVerticalWhitespace(First[0]);
+}
+
static void skipString(const char *&First, const char *const End) {
- assert(*First == '\'' || *First == '"');
- const char Terminator = *First;
- for (++First; First != End && *First != Terminator; ++First)
- if (*First == '\\')
- if (++First == End)
- return;
+ assert(*First == '\'' || *First == '"' || *First == '<');
+ const char Terminator = *First == '<' ? '>' : *First;
+ for (++First; First != End && *First != Terminator; ++First) {
+ // String and character literals don't extend past the end of the line.
+ if (isVerticalWhitespace(*First))
+ return;
+ if (*First != '\\')
+ continue;
+ // Skip past backslash to the next character. This ensures that the
+ // character right after it is skipped as well, which matters if it's
+ // the terminator.
+ if (++First == End)
+ return;
+ if (!isWhitespace(*First))
+ continue;
+ // Whitespace after the backslash might indicate a line continuation.
+ const char *FirstAfterBackslashPastSpace = First;
+ skipOverSpaces(FirstAfterBackslashPastSpace, End);
+ if (unsigned NLSize = isEOL(FirstAfterBackslashPastSpace, End)) {
+ // Advance the character pointer to the next line for the next
+ // iteration.
+ First = FirstAfterBackslashPastSpace + NLSize - 1;
+ }
+ }
if (First != End)
++First; // Finish off the string.
}
-static void skipNewline(const char *&First, const char *End) {
- assert(isVerticalWhitespace(*First));
- ++First;
+// Returns the length of the skipped newline
+static unsigned skipNewline(const char *&First, const char *End) {
if (First == End)
- return;
+ return 0;
+ assert(isVerticalWhitespace(*First));
+ unsigned Len = isEOL(First, End);
+ assert(Len && "expected newline");
+ First += Len;
+ return Len;
+}
- // Check for "\n\r" and "\r\n".
- if (LLVM_UNLIKELY(isVerticalWhitespace(*First) && First[-1] != First[0]))
- ++First;
+static bool wasLineContinuation(const char *First, unsigned EOLLen) {
+ return *(First - (int)EOLLen - 1) == '\\';
}
static void skipToNewlineRaw(const char *&First, const char *const End) {
@@ -211,27 +244,40 @@ static void skipToNewlineRaw(const char *&First, const char *const End) {
if (First == End)
return;
- if (isVerticalWhitespace(*First))
+ unsigned Len = isEOL(First, End);
+ if (Len)
return;
- while (!isVerticalWhitespace(*First))
+ do {
if (++First == End)
return;
+ Len = isEOL(First, End);
+ } while (!Len);
if (First[-1] != '\\')
return;
- ++First; // Keep going...
+ First += Len;
+ // Keep skipping lines...
}
}
-static const char *reverseOverSpaces(const char *First, const char *Last) {
+static const char *findLastNonSpace(const char *First, const char *Last) {
assert(First <= Last);
while (First != Last && isHorizontalWhitespace(Last[-1]))
--Last;
return Last;
}
+static const char *findFirstTrailingSpace(const char *First,
+ const char *Last) {
+ const char *LastNonSpace = findLastNonSpace(First, Last);
+ if (Last == LastNonSpace)
+ return Last;
+ assert(isHorizontalWhitespace(LastNonSpace[0]));
+ return LastNonSpace + 1;
+}
+
static void skipLineComment(const char *&First, const char *const End) {
assert(First[0] == '/' && First[1] == '/');
First += 2;
@@ -276,7 +322,7 @@ static bool isQuoteCppDigitSeparator(const char *const Start,
}
static void skipLine(const char *&First, const char *const End) {
- do {
+ for (;;) {
assert(First <= End);
if (First == End)
return;
@@ -321,9 +367,10 @@ static void skipLine(const char *&First, const char *const End) {
return;
// Skip over the newline.
- assert(isVerticalWhitespace(*First));
- skipNewline(First, End);
- } while (First[-2] == '\\'); // Continue past line-continuations.
+ unsigned Len = skipNewline(First, End);
+ if (!wasLineContinuation(First, Len)) // Continue past line-continuations.
+ break;
+ }
}
static void skipDirective(StringRef Name, const char *&First,
@@ -343,7 +390,8 @@ void Minimizer::printToNewline(const char *&First, const char *const End) {
const char *Last = First;
do {
// Iterate over strings correctly to avoid comments and newlines.
- if (*Last == '"' || *Last == '\'') {
+ if (*Last == '"' || *Last == '\'' ||
+ (*Last == '<' && top() == pp_include)) {
if (LLVM_UNLIKELY(isRawStringLiteral(First, Last)))
skipRawString(Last, End);
else
@@ -361,7 +409,7 @@ void Minimizer::printToNewline(const char *&First, const char *const End) {
}
// Deal with "//..." and "/*...*/".
- append(First, reverseOverSpaces(First, Last));
+ append(First, findFirstTrailingSpace(First, Last));
First = Last;
if (Last[1] == '/') {
@@ -376,13 +424,20 @@ void Minimizer::printToNewline(const char *&First, const char *const End) {
} while (Last != End && !isVerticalWhitespace(*Last));
// Print out the string.
- if (Last == End || Last == First || Last[-1] != '\\') {
- append(First, reverseOverSpaces(First, Last));
+ const char *LastBeforeTrailingSpace = findLastNonSpace(First, Last);
+ if (Last == End || LastBeforeTrailingSpace == First ||
+ LastBeforeTrailingSpace[-1] != '\\') {
+ append(First, LastBeforeTrailingSpace);
+ First = Last;
+ skipNewline(First, End);
return;
}
- // Print up to the backslash, backing up over spaces.
- append(First, reverseOverSpaces(First, Last - 1));
+ // Print up to the backslash, backing up over spaces. Preserve at least one
+ // space, as the space matters when tokens are separated by a line
+ // continuation.
+ append(First, findFirstTrailingSpace(
+ First, LastBeforeTrailingSpace - 1));
First = Last;
skipNewline(First, End);
@@ -576,6 +631,59 @@ bool Minimizer::lexAt(const char *&First, const char *const End) {
return false;
}
+bool Minimizer::lexModule(const char *&First, const char *const End) {
+ IdInfo Id = lexIdentifier(First, End);
+ First = Id.Last;
+ bool Export = false;
+ if (Id.Name == "export") {
+ Export = true;
+ skipWhitespace(First, End);
+ if (!isIdentifierBody(*First)) {
+ skipLine(First, End);
+ return false;
+ }
+ Id = lexIdentifier(First, End);
+ First = Id.Last;
+ }
+
+ if (Id.Name != "module" && Id.Name != "import") {
+ skipLine(First, End);
+ return false;
+ }
+
+ skipWhitespace(First, End);
+
+ // Ignore this as a module directive if the next character can't be part of
+ // an import.
+
+ switch (*First) {
+ case ':':
+ case '<':
+ case '"':
+ break;
+ default:
+ if (!isIdentifierBody(*First)) {
+ skipLine(First, End);
+ return false;
+ }
+ }
+
+ if (Export) {
+ makeToken(cxx_export_decl);
+ append("export ");
+ }
+
+ if (Id.Name == "module")
+ makeToken(cxx_module_decl);
+ else
+ makeToken(cxx_import_decl);
+ append(Id.Name);
+ append(" ");
+ printToNewline(First, End);
+ append("\n");
+ return false;
+}
+
bool Minimizer::lexDefine(const char *&First, const char *const End) {
makeToken(pp_define);
append("#define ");
@@ -612,7 +720,21 @@ bool Minimizer::lexDefine(const char *&First, const char *const End) {
bool Minimizer::lexPragma(const char *&First, const char *const End) {
// #pragma.
- if (!isNextIdentifier("clang", First, End)) {
+ skipWhitespace(First, End);
+ if (First == End || !isIdentifierHead(*First))
+ return false;
+
+ IdInfo FoundId = lexIdentifier(First, End);
+ First = FoundId.Last;
+ if (FoundId.Name == "once") {
+ // #pragma once
+ skipLine(First, End);
+ makeToken(pp_pragma_once);
+ append("#pragma once\n");
+ return false;
+ }
+
+ if (FoundId.Name != "clang") {
skipLine(First, End);
return false;
}
@@ -663,6 +785,18 @@ bool Minimizer::lexDefault(TokenKind Kind, StringRef Directive,
return false;
}
+static bool isStartOfRelevantLine(char First) {
+ switch (First) {
+ case '#':
+ case '@':
+ case 'i':
+ case 'e':
+ case 'm':
+ return true;
+ }
+ return false;
+}
+
bool Minimizer::lexPPLine(const char *&First, const char *const End) {
assert(First != End);
@@ -671,7 +805,7 @@ bool Minimizer::lexPPLine(const char *&First, const char *const End) {
if (First == End)
return false;
- if (*First != '#' && *First != '@') {
+ if (!isStartOfRelevantLine(*First)) {
skipLine(First, End);
assert(First <= End);
return false;
@@ -681,6 +815,9 @@ bool Minimizer::lexPPLine(const char *&First, const char *const End) {
if (*First == '@')
return lexAt(First, End);
+ if (*First == 'i' || *First == 'e' || *First == 'm')
+ return lexModule(First, End);
+
// Handle preprocessing directives.
++First; // Skip over '#'.
skipWhitespace(First, End);
@@ -729,7 +866,14 @@ bool Minimizer::lexPPLine(const char *&First, const char *const End) {
return lexDefault(Kind, Id.Name, First, End);
}
+static void skipUTF8ByteOrderMark(const char *&First, const char *const End) {
+ if ((End - First) >= 3 && First[0] == '\xef' && First[1] == '\xbb' &&
+ First[2] == '\xbf')
+ First += 3;
+}
+
bool Minimizer::minimizeImpl(const char *First, const char *const End) {
+ skipUTF8ByteOrderMark(First, End);
while (First != End)
if (lexPPLine(First, End))
return true;
@@ -753,6 +897,54 @@ bool Minimizer::minimize() {
return Error;
}
+bool clang::minimize_source_to_dependency_directives::computeSkippedRanges(
+ ArrayRef<Token> Input, llvm::SmallVectorImpl<SkippedRange> &Range) {
+ struct Directive {
+ enum DirectiveKind {
+ If, // if/ifdef/ifndef
+ Else // elif,else
+ };
+ int Offset;
+ DirectiveKind Kind;
+ };
+ llvm::SmallVector<Directive, 32> Offsets;
+ for (const Token &T : Input) {
+ switch (T.K) {
+ case pp_if:
+ case pp_ifdef:
+ case pp_ifndef:
+ Offsets.push_back({T.Offset, Directive::If});
+ break;
+
+ case pp_elif:
+ case pp_else: {
+ if (Offsets.empty())
+ return true;
+ int PreviousOffset = Offsets.back().Offset;
+ Range.push_back({PreviousOffset, T.Offset - PreviousOffset});
+ Offsets.push_back({T.Offset, Directive::Else});
+ break;
+ }
+
+ case pp_endif: {
+ if (Offsets.empty())
+ return true;
+ int PreviousOffset = Offsets.back().Offset;
+ Range.push_back({PreviousOffset, T.Offset - PreviousOffset});
+ do {
+ Directive::DirectiveKind Kind = Offsets.pop_back_val().Kind;
+ if (Kind == Directive::If)
+ break;
+ } while (!Offsets.empty());
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
bool clang::minimizeSourceToDependencyDirectives(
StringRef Input, SmallVectorImpl<char> &Output,
SmallVectorImpl<Token> &Tokens, DiagnosticsEngine *Diags,
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
index e0bf58b67505..d44ef29c05d1 100644
--- a/lib/Lex/HeaderMap.cpp
+++ b/lib/Lex/HeaderMap.cpp
@@ -196,15 +196,15 @@ LLVM_DUMP_METHOD void HeaderMapImpl::dump() const {
/// LookupFile - Check to see if the specified relative filename is located in
/// this HeaderMap. If so, open it and return its FileEntry.
-const FileEntry *HeaderMap::LookupFile(
- StringRef Filename, FileManager &FM) const {
+Optional<FileEntryRef> HeaderMap::LookupFile(StringRef Filename,
+ FileManager &FM) const {
SmallString<1024> Path;
StringRef Dest = HeaderMapImpl::lookupFilename(Filename, Path);
if (Dest.empty())
- return nullptr;
+ return None;
- return FM.getFile(Dest);
+ return FM.getOptionalFileRef(Dest);
}
StringRef HeaderMapImpl::lookupFilename(StringRef Filename,
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 108630cc26f6..f0c5900c8ce4 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -27,9 +27,11 @@
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Capacity.h"
+#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
@@ -45,6 +47,16 @@
using namespace clang;
+#define DEBUG_TYPE "file-search"
+
+ALWAYS_ENABLED_STATISTIC(NumIncluded, "Number of attempted #includes.");
+ALWAYS_ENABLED_STATISTIC(
+ NumMultiIncludeFileOptzn,
+ "Number of #includes skipped due to the multi-include optimization.");
+ALWAYS_ENABLED_STATISTIC(NumFrameworkLookups, "Number of framework lookups.");
+ALWAYS_ENABLED_STATISTIC(NumSubFrameworkLookups,
+ "Number of subframework lookups.");
+
const IdentifierInfo *
HeaderFileInfo::getControllingMacro(ExternalPreprocessorSource *External) {
if (ControllingMacro) {
@@ -75,8 +87,8 @@ HeaderSearch::HeaderSearch(std::shared_ptr<HeaderSearchOptions> HSOpts,
ModMap(SourceMgr, Diags, LangOpts, Target, *this) {}
void HeaderSearch::PrintStats() {
- fprintf(stderr, "\n*** HeaderSearch Stats:\n");
- fprintf(stderr, "%d files tracked.\n", (int)FileInfo.size());
+ llvm::errs() << "\n*** HeaderSearch Stats:\n"
+ << FileInfo.size() << " files tracked.\n";
unsigned NumOnceOnlyFiles = 0, MaxNumIncludes = 0, NumSingleIncludedFiles = 0;
for (unsigned i = 0, e = FileInfo.size(); i != e; ++i) {
NumOnceOnlyFiles += FileInfo[i].isImport;
@@ -84,16 +96,16 @@ void HeaderSearch::PrintStats() {
MaxNumIncludes = FileInfo[i].NumIncludes;
NumSingleIncludedFiles += FileInfo[i].NumIncludes == 1;
}
- fprintf(stderr, " %d #import/#pragma once files.\n", NumOnceOnlyFiles);
- fprintf(stderr, " %d included exactly once.\n", NumSingleIncludedFiles);
- fprintf(stderr, " %d max times a file is included.\n", MaxNumIncludes);
+ llvm::errs() << " " << NumOnceOnlyFiles << " #import/#pragma once files.\n"
+ << " " << NumSingleIncludedFiles << " included exactly once.\n"
+ << " " << MaxNumIncludes << " max times a file is included.\n";
- fprintf(stderr, " %d #include/#include_next/#import.\n", NumIncluded);
- fprintf(stderr, " %d #includes skipped due to"
- " the multi-include optimization.\n", NumMultiIncludeFileOptzn);
+ llvm::errs() << " " << NumIncluded << " #include/#include_next/#import.\n"
+ << " " << NumMultiIncludeFileOptzn
+ << " #includes skipped due to the multi-include optimization.\n";
- fprintf(stderr, "%d framework lookups.\n", NumFrameworkLookups);
- fprintf(stderr, "%d subframework lookups.\n", NumSubFrameworkLookups);
+ llvm::errs() << NumFrameworkLookups << " framework lookups.\n"
+ << NumSubFrameworkLookups << " subframework lookups.\n";
}
/// CreateHeaderMap - This method returns a HeaderMap for the specified
@@ -175,10 +187,10 @@ std::string HeaderSearch::getCachedModuleFileName(StringRef ModuleName,
std::string Parent = llvm::sys::path::parent_path(ModuleMapPath);
if (Parent.empty())
Parent = ".";
- auto *Dir = FileMgr.getDirectory(Parent);
+ auto Dir = FileMgr.getDirectory(Parent);
if (!Dir)
return {};
- auto DirName = FileMgr.getCanonicalName(Dir);
+ auto DirName = FileMgr.getCanonicalName(*Dir);
auto FileName = llvm::sys::path::filename(ModuleMapPath);
llvm::hash_code Hash =
@@ -230,11 +242,10 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName,
SmallString<128> FrameworkDirName;
FrameworkDirName += SearchDirs[Idx].getFrameworkDir()->getName();
llvm::sys::path::append(FrameworkDirName, SearchName + ".framework");
- if (const DirectoryEntry *FrameworkDir
- = FileMgr.getDirectory(FrameworkDirName)) {
+ if (auto FrameworkDir = FileMgr.getDirectory(FrameworkDirName)) {
bool IsSystem
= SearchDirs[Idx].getDirCharacteristic() != SrcMgr::C_User;
- Module = loadFrameworkModule(ModuleName, FrameworkDir, IsSystem);
+ Module = loadFrameworkModule(ModuleName, *FrameworkDir, IsSystem);
if (Module)
break;
}
@@ -296,6 +307,7 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName,
/// getName - Return the directory or filename corresponding to this lookup
/// object.
StringRef DirectoryLookup::getName() const {
+ // FIXME: Use the name from \c DirectoryEntryRef.
if (isNormalDir())
return getDir()->getName();
if (isFramework())
@@ -304,41 +316,46 @@ StringRef DirectoryLookup::getName() const {
return getHeaderMap()->getFileName();
}
-const FileEntry *HeaderSearch::getFileAndSuggestModule(
+Optional<FileEntryRef> HeaderSearch::getFileAndSuggestModule(
StringRef FileName, SourceLocation IncludeLoc, const DirectoryEntry *Dir,
bool IsSystemHeaderDir, Module *RequestingModule,
ModuleMap::KnownHeader *SuggestedModule) {
// If we have a module map that might map this header, load it and
// check whether we'll have a suggestion for a module.
- const FileEntry *File = getFileMgr().getFile(FileName, /*OpenFile=*/true);
- if (!File)
- return nullptr;
+ auto File = getFileMgr().getFileRef(FileName, /*OpenFile=*/true);
+ if (!File) {
+ // For rare, surprising errors (e.g. "out of file handles"), diag the EC
+ // message.
+ std::error_code EC = llvm::errorToErrorCode(File.takeError());
+ if (EC != llvm::errc::no_such_file_or_directory &&
+ EC != llvm::errc::invalid_argument &&
+ EC != llvm::errc::is_a_directory && EC != llvm::errc::not_a_directory) {
+ Diags.Report(IncludeLoc, diag::err_cannot_open_file)
+ << FileName << EC.message();
+ }
+ return None;
+ }
// If there is a module that corresponds to this header, suggest it.
- if (!findUsableModuleForHeader(File, Dir ? Dir : File->getDir(),
- RequestingModule, SuggestedModule,
- IsSystemHeaderDir))
- return nullptr;
+ if (!findUsableModuleForHeader(
+ &File->getFileEntry(), Dir ? Dir : File->getFileEntry().getDir(),
+ RequestingModule, SuggestedModule, IsSystemHeaderDir))
+ return None;
- return File;
+ return *File;
}
/// LookupFile - Lookup the specified file in this search path, returning it
/// if it exists or returning null if not.
-const FileEntry *DirectoryLookup::LookupFile(
- StringRef &Filename,
- HeaderSearch &HS,
- SourceLocation IncludeLoc,
- SmallVectorImpl<char> *SearchPath,
- SmallVectorImpl<char> *RelativePath,
- Module *RequestingModule,
- ModuleMap::KnownHeader *SuggestedModule,
- bool &InUserSpecifiedSystemFramework,
- bool &IsFrameworkFound,
- bool &HasBeenMapped,
- SmallVectorImpl<char> &MappedName) const {
+Optional<FileEntryRef> DirectoryLookup::LookupFile(
+ StringRef &Filename, HeaderSearch &HS, SourceLocation IncludeLoc,
+ SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
+ Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule,
+ bool &InUserSpecifiedSystemFramework, bool &IsFrameworkFound,
+ bool &IsInHeaderMap, SmallVectorImpl<char> &MappedName) const {
InUserSpecifiedSystemFramework = false;
- HasBeenMapped = false;
+ IsInHeaderMap = false;
+ MappedName.clear();
SmallString<1024> TmpDir;
if (isNormalDir()) {
@@ -370,24 +387,11 @@ const FileEntry *DirectoryLookup::LookupFile(
SmallString<1024> Path;
StringRef Dest = HM->lookupFilename(Filename, Path);
if (Dest.empty())
- return nullptr;
+ return None;
- const FileEntry *Result;
-
- // Check if the headermap maps the filename to a framework include
- // ("Foo.h" -> "Foo/Foo.h"), in which case continue header lookup using the
- // framework include.
- if (llvm::sys::path::is_relative(Dest)) {
- MappedName.clear();
- MappedName.append(Dest.begin(), Dest.end());
- Filename = StringRef(MappedName.begin(), MappedName.size());
- HasBeenMapped = true;
- Result = HM->LookupFile(Filename, HS.getFileMgr());
- } else {
- Result = HS.getFileMgr().getFile(Dest);
- }
+ IsInHeaderMap = true;
- if (Result) {
+ auto FixupSearchPath = [&]() {
if (SearchPath) {
StringRef SearchPathRef(getName());
SearchPath->clear();
@@ -397,8 +401,25 @@ const FileEntry *DirectoryLookup::LookupFile(
RelativePath->clear();
RelativePath->append(Filename.begin(), Filename.end());
}
+ };
+
+ // Check if the headermap maps the filename to a framework include
+ // ("Foo.h" -> "Foo/Foo.h"), in which case continue header lookup using the
+ // framework include.
+ if (llvm::sys::path::is_relative(Dest)) {
+ MappedName.append(Dest.begin(), Dest.end());
+ Filename = StringRef(MappedName.begin(), MappedName.size());
+ Optional<FileEntryRef> Result = HM->LookupFile(Filename, HS.getFileMgr());
+ if (Result) {
+ FixupSearchPath();
+ return *Result;
+ }
+ } else if (auto Res = HS.getFileMgr().getOptionalFileRef(Dest)) {
+ FixupSearchPath();
+ return *Res;
}
- return Result;
+
+ return None;
}
/// Given a framework directory, find the top-most framework directory.
@@ -427,8 +448,12 @@ getTopFrameworkDir(FileManager &FileMgr, StringRef DirName,
//
// Similar issues occur when a top-level framework has moved into an
// embedded framework.
- const DirectoryEntry *TopFrameworkDir = FileMgr.getDirectory(DirName);
- DirName = FileMgr.getCanonicalName(TopFrameworkDir);
+ const DirectoryEntry *TopFrameworkDir = nullptr;
+ if (auto TopFrameworkDirOrErr = FileMgr.getDirectory(DirName))
+ TopFrameworkDir = *TopFrameworkDirOrErr;
+
+ if (TopFrameworkDir)
+ DirName = FileMgr.getCanonicalName(TopFrameworkDir);
do {
// Get the parent directory name.
DirName = llvm::sys::path::parent_path(DirName);
@@ -436,7 +461,7 @@ getTopFrameworkDir(FileManager &FileMgr, StringRef DirName,
break;
// Determine whether this directory exists.
- const DirectoryEntry *Dir = FileMgr.getDirectory(DirName);
+ auto Dir = FileMgr.getDirectory(DirName);
if (!Dir)
break;
@@ -444,7 +469,7 @@ getTopFrameworkDir(FileManager &FileMgr, StringRef DirName,
// framework.
if (llvm::sys::path::extension(DirName) == ".framework") {
SubmodulePath.push_back(llvm::sys::path::stem(DirName));
- TopFrameworkDir = Dir;
+ TopFrameworkDir = *Dir;
}
} while (true);
@@ -459,7 +484,7 @@ static bool needModuleLookup(Module *RequestingModule,
/// DoFrameworkLookup - Do a lookup of the specified file in the current
/// DirectoryLookup, which is a framework directory.
-const FileEntry *DirectoryLookup::DoFrameworkLookup(
+Optional<FileEntryRef> DirectoryLookup::DoFrameworkLookup(
StringRef Filename, HeaderSearch &HS, SmallVectorImpl<char> *SearchPath,
SmallVectorImpl<char> *RelativePath, Module *RequestingModule,
ModuleMap::KnownHeader *SuggestedModule,
@@ -468,7 +493,8 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
// Framework names must have a '/' in the filename.
size_t SlashPos = Filename.find('/');
- if (SlashPos == StringRef::npos) return nullptr;
+ if (SlashPos == StringRef::npos)
+ return None;
// Find out if this is the home for the specified framework, by checking
// HeaderSearch. Possible answers are yes/no and unknown.
@@ -477,13 +503,13 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
// If it is known and in some other directory, fail.
if (CacheEntry.Directory && CacheEntry.Directory != getFrameworkDir())
- return nullptr;
+ return None;
// Otherwise, construct the path to this framework dir.
// FrameworkName = "/System/Library/Frameworks/"
SmallString<1024> FrameworkName;
- FrameworkName += getFrameworkDir()->getName();
+ FrameworkName += getFrameworkDirRef()->getName();
if (FrameworkName.empty() || FrameworkName.back() != '/')
FrameworkName.push_back('/');
@@ -496,11 +522,12 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
// If the cache entry was unresolved, populate it now.
if (!CacheEntry.Directory) {
- HS.IncrementFrameworkLookupCount();
+ ++NumFrameworkLookups;
// If the framework dir doesn't exist, we fail.
- const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName);
- if (!Dir) return nullptr;
+ auto Dir = FileMgr.getDirectory(FrameworkName);
+ if (!Dir)
+ return None;
// Otherwise, if it does, remember that this is the right direntry for this
// framework.
@@ -538,9 +565,10 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
}
FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
- const FileEntry *FE = FileMgr.getFile(FrameworkName,
- /*OpenFile=*/!SuggestedModule);
- if (!FE) {
+
+ auto File =
+ FileMgr.getOptionalFileRef(FrameworkName, /*OpenFile=*/!SuggestedModule);
+ if (!File) {
// Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
const char *Private = "Private";
FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
@@ -549,17 +577,18 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
SearchPath->insert(SearchPath->begin()+OrigSize, Private,
Private+strlen(Private));
- FE = FileMgr.getFile(FrameworkName, /*OpenFile=*/!SuggestedModule);
+ File = FileMgr.getOptionalFileRef(FrameworkName,
+ /*OpenFile=*/!SuggestedModule);
}
// If we found the header and are allowed to suggest a module, do so now.
- if (FE && needModuleLookup(RequestingModule, SuggestedModule)) {
+ if (File && needModuleLookup(RequestingModule, SuggestedModule)) {
// Find the framework in which this header occurs.
- StringRef FrameworkPath = FE->getDir()->getName();
+ StringRef FrameworkPath = File->getFileEntry().getDir()->getName();
bool FoundFramework = false;
do {
// Determine whether this directory exists.
- const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkPath);
+ auto Dir = FileMgr.getDirectory(FrameworkPath);
if (!Dir)
break;
@@ -579,15 +608,19 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
if (FoundFramework) {
if (!HS.findUsableModuleForFrameworkHeader(
- FE, FrameworkPath, RequestingModule, SuggestedModule, IsSystem))
- return nullptr;
+ &File->getFileEntry(), FrameworkPath, RequestingModule,
+ SuggestedModule, IsSystem))
+ return None;
} else {
- if (!HS.findUsableModuleForHeader(FE, getDir(), RequestingModule,
- SuggestedModule, IsSystem))
- return nullptr;
+ if (!HS.findUsableModuleForHeader(&File->getFileEntry(), getDir(),
+ RequestingModule, SuggestedModule,
+ IsSystem))
+ return None;
}
}
- return FE;
+ if (File)
+ return *File;
+ return None;
}
void HeaderSearch::setTarget(const TargetInfo &Target) {
@@ -692,7 +725,7 @@ diagnoseFrameworkInclude(DiagnosticsEngine &Diags, SourceLocation IncludeLoc,
/// for system \#include's or not (i.e. using <> instead of ""). Includers, if
/// non-empty, indicates where the \#including file(s) are, in case a relative
/// search is needed. Microsoft mode will pass all \#including files.
-const FileEntry *HeaderSearch::LookupFile(
+Optional<FileEntryRef> HeaderSearch::LookupFile(
StringRef Filename, SourceLocation IncludeLoc, bool isAngled,
const DirectoryLookup *FromDir, const DirectoryLookup *&CurDir,
ArrayRef<std::pair<const FileEntry *, const DirectoryEntry *>> Includers,
@@ -714,7 +747,8 @@ const FileEntry *HeaderSearch::LookupFile(
CurDir = nullptr;
// If this was an #include_next "/absolute/file", fail.
- if (FromDir) return nullptr;
+ if (FromDir)
+ return None;
if (SearchPath)
SearchPath->clear();
@@ -729,8 +763,9 @@ const FileEntry *HeaderSearch::LookupFile(
}
// This is the header that MSVC's header search would have found.
- const FileEntry *MSFE = nullptr;
ModuleMap::KnownHeader MSSuggestedModule;
+ const FileEntry *MSFE_FE = nullptr;
+ StringRef MSFE_Name;
// Unless disabled, check to see if the file is in the #includer's
// directory. This cannot be based on CurDir, because each includer could be
@@ -759,7 +794,7 @@ const FileEntry *HeaderSearch::LookupFile(
bool IncluderIsSystemHeader =
Includer ? getFileInfo(Includer).DirInfo != SrcMgr::C_User :
BuildSystemModule;
- if (const FileEntry *FE = getFileAndSuggestModule(
+ if (Optional<FileEntryRef> FE = getFileAndSuggestModule(
TmpDir, IncludeLoc, IncluderAndDir.second, IncluderIsSystemHeader,
RequestingModule, SuggestedModule)) {
if (!Includer) {
@@ -778,7 +813,7 @@ const FileEntry *HeaderSearch::LookupFile(
bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader;
StringRef Framework = FromHFI.Framework;
- HeaderFileInfo &ToHFI = getFileInfo(FE);
+ HeaderFileInfo &ToHFI = getFileInfo(&FE->getFileEntry());
ToHFI.DirInfo = DirInfo;
ToHFI.IndexHeaderMapHeader = IndexHeaderMapHeader;
ToHFI.Framework = Framework;
@@ -795,7 +830,7 @@ const FileEntry *HeaderSearch::LookupFile(
if (First) {
diagnoseFrameworkInclude(Diags, IncludeLoc,
IncluderAndDir.second->getName(), Filename,
- FE);
+ &FE->getFileEntry());
return FE;
}
@@ -805,7 +840,8 @@ const FileEntry *HeaderSearch::LookupFile(
if (Diags.isIgnored(diag::ext_pp_include_search_ms, IncludeLoc)) {
return FE;
} else {
- MSFE = FE;
+ MSFE_FE = &FE->getFileEntry();
+ MSFE_Name = FE->getName();
if (SuggestedModule) {
MSSuggestedModule = *SuggestedModule;
*SuggestedModule = ModuleMap::KnownHeader();
@@ -817,6 +853,9 @@ const FileEntry *HeaderSearch::LookupFile(
}
}
+ Optional<FileEntryRef> MSFE(MSFE_FE ? FileEntryRef(MSFE_Name, *MSFE_FE)
+ : Optional<FileEntryRef>());
+
CurDir = nullptr;
// If this is a system #include, ignore the user #include locs.
@@ -856,29 +895,34 @@ const FileEntry *HeaderSearch::LookupFile(
// Check each directory in sequence to see if it contains this file.
for (; i != SearchDirs.size(); ++i) {
bool InUserSpecifiedSystemFramework = false;
- bool HasBeenMapped = false;
+ bool IsInHeaderMap = false;
bool IsFrameworkFoundInDir = false;
- const FileEntry *FE = SearchDirs[i].LookupFile(
+ Optional<FileEntryRef> File = SearchDirs[i].LookupFile(
Filename, *this, IncludeLoc, SearchPath, RelativePath, RequestingModule,
SuggestedModule, InUserSpecifiedSystemFramework, IsFrameworkFoundInDir,
- HasBeenMapped, MappedName);
- if (HasBeenMapped) {
+ IsInHeaderMap, MappedName);
+ if (!MappedName.empty()) {
+ assert(IsInHeaderMap && "MappedName should come from a header map");
CacheLookup.MappedName =
- copyString(Filename, LookupFileCache.getAllocator());
- if (IsMapped)
- *IsMapped = true;
+ copyString(MappedName, LookupFileCache.getAllocator());
}
+ if (IsMapped)
+ // A filename is mapped when a header map remapped it to a relative path
+ // used in subsequent header search or to an absolute path pointing to an
+ // existing file.
+ *IsMapped |= (!MappedName.empty() || (IsInHeaderMap && File));
if (IsFrameworkFound)
// Because we keep a filename remapped for subsequent search directory
// lookups, ignore IsFrameworkFoundInDir after the first remapping and not
// just for remapping in a current search directory.
*IsFrameworkFound |= (IsFrameworkFoundInDir && !CacheLookup.MappedName);
- if (!FE) continue;
+ if (!File)
+ continue;
CurDir = &SearchDirs[i];
// This file is a system header or C++ unfriendly if the dir is.
- HeaderFileInfo &HFI = getFileInfo(FE);
+ HeaderFileInfo &HFI = getFileInfo(&File->getFileEntry());
HFI.DirInfo = CurDir->getDirCharacteristic();
// If the directory characteristic is User but this framework was
@@ -908,7 +952,8 @@ const FileEntry *HeaderSearch::LookupFile(
}
}
- if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
+ if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr,
+ &File->getFileEntry(), IncludeLoc)) {
if (SuggestedModule)
*SuggestedModule = MSSuggestedModule;
return MSFE;
@@ -916,13 +961,13 @@ const FileEntry *HeaderSearch::LookupFile(
bool FoundByHeaderMap = !IsMapped ? false : *IsMapped;
if (!Includers.empty())
- diagnoseFrameworkInclude(Diags, IncludeLoc,
- Includers.front().second->getName(), Filename,
- FE, isAngled, FoundByHeaderMap);
+ diagnoseFrameworkInclude(
+ Diags, IncludeLoc, Includers.front().second->getName(), Filename,
+ &File->getFileEntry(), isAngled, FoundByHeaderMap);
// Remember this location for the next lookup we do.
CacheLookup.HitIdx = i;
- return FE;
+ return File;
}
// If we are including a file with a quoted include "foo.h" from inside
@@ -938,12 +983,14 @@ const FileEntry *HeaderSearch::LookupFile(
ScratchFilename += '/';
ScratchFilename += Filename;
- const FileEntry *FE = LookupFile(
+ Optional<FileEntryRef> File = LookupFile(
ScratchFilename, IncludeLoc, /*isAngled=*/true, FromDir, CurDir,
Includers.front(), SearchPath, RelativePath, RequestingModule,
SuggestedModule, IsMapped, /*IsFrameworkFound=*/nullptr);
- if (checkMSVCHeaderSearch(Diags, MSFE, FE, IncludeLoc)) {
+ if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr,
+ File ? &File->getFileEntry() : nullptr,
+ IncludeLoc)) {
if (SuggestedModule)
*SuggestedModule = MSSuggestedModule;
return MSFE;
@@ -952,11 +999,12 @@ const FileEntry *HeaderSearch::LookupFile(
LookupFileCacheInfo &CacheLookup = LookupFileCache[Filename];
CacheLookup.HitIdx = LookupFileCache[ScratchFilename].HitIdx;
// FIXME: SuggestedModule.
- return FE;
+ return File;
}
}
- if (checkMSVCHeaderSearch(Diags, MSFE, nullptr, IncludeLoc)) {
+ if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr,
+ nullptr, IncludeLoc)) {
if (SuggestedModule)
*SuggestedModule = MSSuggestedModule;
return MSFE;
@@ -964,7 +1012,7 @@ const FileEntry *HeaderSearch::LookupFile(
// Otherwise, didn't find it. Remember we didn't find this.
CacheLookup.HitIdx = SearchDirs.size();
- return nullptr;
+ return None;
}
/// LookupSubframeworkHeader - Look up a subframework for the specified
@@ -972,19 +1020,17 @@ const FileEntry *HeaderSearch::LookupFile(
/// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
/// is a subframework within Carbon.framework. If so, return the FileEntry
/// for the designated file, otherwise return null.
-const FileEntry *HeaderSearch::
-LookupSubframeworkHeader(StringRef Filename,
- const FileEntry *ContextFileEnt,
- SmallVectorImpl<char> *SearchPath,
- SmallVectorImpl<char> *RelativePath,
- Module *RequestingModule,
- ModuleMap::KnownHeader *SuggestedModule) {
+Optional<FileEntryRef> HeaderSearch::LookupSubframeworkHeader(
+ StringRef Filename, const FileEntry *ContextFileEnt,
+ SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath,
+ Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule) {
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 nullptr;
+ if (SlashPos == StringRef::npos)
+ return None;
// Look up the base framework name of the ContextFileEnt.
StringRef ContextName = ContextFileEnt->getName();
@@ -995,7 +1041,7 @@ LookupSubframeworkHeader(StringRef Filename,
if (FrameworkPos == StringRef::npos ||
(ContextName[FrameworkPos + DotFrameworkLen] != '/' &&
ContextName[FrameworkPos + DotFrameworkLen] != '\\'))
- return nullptr;
+ return None;
SmallString<1024> FrameworkName(ContextName.data(), ContextName.data() +
FrameworkPos +
@@ -1015,22 +1061,22 @@ LookupSubframeworkHeader(StringRef Filename,
CacheLookup.first().size() == FrameworkName.size() &&
memcmp(CacheLookup.first().data(), &FrameworkName[0],
CacheLookup.first().size()) != 0)
- return nullptr;
+ return None;
// Cache subframework.
if (!CacheLookup.second.Directory) {
++NumSubFrameworkLookups;
// If the framework dir doesn't exist, we fail.
- const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkName);
- if (!Dir) return nullptr;
+ auto Dir = FileMgr.getDirectory(FrameworkName);
+ if (!Dir)
+ return None;
// Otherwise, if it does, remember that this is the right direntry for this
// framework.
- CacheLookup.second.Directory = Dir;
+ CacheLookup.second.Directory = *Dir;
}
- const FileEntry *FE = nullptr;
if (RelativePath) {
RelativePath->clear();
@@ -1047,7 +1093,8 @@ LookupSubframeworkHeader(StringRef Filename,
}
HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
- if (!(FE = FileMgr.getFile(HeadersFilename, /*OpenFile=*/true))) {
+ auto File = FileMgr.getOptionalFileRef(HeadersFilename, /*OpenFile=*/true);
+ if (!File) {
// Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h"
HeadersFilename = FrameworkName;
HeadersFilename += "PrivateHeaders/";
@@ -1058,8 +1105,10 @@ LookupSubframeworkHeader(StringRef Filename,
}
HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end());
- if (!(FE = FileMgr.getFile(HeadersFilename, /*OpenFile=*/true)))
- return nullptr;
+ File = FileMgr.getOptionalFileRef(HeadersFilename, /*OpenFile=*/true);
+
+ if (!File)
+ return None;
}
// This file is a system header or C++ unfriendly if the old file is.
@@ -1068,14 +1117,15 @@ LookupSubframeworkHeader(StringRef Filename,
// getFileInfo could resize the vector and we don't want to rely on order
// of evaluation.
unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo;
- getFileInfo(FE).DirInfo = DirInfo;
+ getFileInfo(&File->getFileEntry()).DirInfo = DirInfo;
FrameworkName.pop_back(); // remove the trailing '/'
- if (!findUsableModuleForFrameworkHeader(FE, FrameworkName, RequestingModule,
- SuggestedModule, /*IsSystem*/ false))
- return nullptr;
+ if (!findUsableModuleForFrameworkHeader(&File->getFileEntry(), FrameworkName,
+ RequestingModule, SuggestedModule,
+ /*IsSystem*/ false))
+ return None;
- return FE;
+ return *File;
}
//===----------------------------------------------------------------------===//
@@ -1306,13 +1356,13 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
return false;
// Determine whether this directory exists.
- const DirectoryEntry *Dir = FileMgr.getDirectory(DirName);
+ auto Dir = FileMgr.getDirectory(DirName);
if (!Dir)
return false;
// Try to load the module map file in this directory.
- switch (loadModuleMapFile(Dir, IsSystem,
- llvm::sys::path::extension(Dir->getName()) ==
+ switch (loadModuleMapFile(*Dir, IsSystem,
+ llvm::sys::path::extension((*Dir)->getName()) ==
".framework")) {
case LMM_NewlyLoaded:
case LMM_AlreadyLoaded:
@@ -1328,12 +1378,12 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
}
// If we hit the top of our search, we're done.
- if (Dir == Root)
+ 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);
+ FixUpDirectories.push_back(*Dir);
} while (true);
}
@@ -1417,7 +1467,9 @@ static const FileEntry *getPrivateModuleMap(const FileEntry *File,
llvm::sys::path::append(PrivateFilename, "module.private.modulemap");
else
return nullptr;
- return FileMgr.getFile(PrivateFilename);
+ if (auto File = FileMgr.getFile(PrivateFilename))
+ return *File;
+ return nullptr;
}
bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem,
@@ -1426,15 +1478,18 @@ bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem,
// Find the directory for the module. For frameworks, that may require going
// up from the 'Modules' directory.
const DirectoryEntry *Dir = nullptr;
- if (getHeaderSearchOpts().ModuleMapFileHomeIsCwd)
- Dir = FileMgr.getDirectory(".");
- else {
+ if (getHeaderSearchOpts().ModuleMapFileHomeIsCwd) {
+ if (auto DirOrErr = FileMgr.getDirectory("."))
+ Dir = *DirOrErr;
+ } else {
if (!OriginalModuleMapFile.empty()) {
// We're building a preprocessed module map. Find or invent the directory
// that it originally occupied.
- Dir = FileMgr.getDirectory(
+ auto DirOrErr = FileMgr.getDirectory(
llvm::sys::path::parent_path(OriginalModuleMapFile));
- if (!Dir) {
+ if (DirOrErr) {
+ Dir = *DirOrErr;
+ } else {
auto *FakeFile = FileMgr.getVirtualFile(OriginalModuleMapFile, 0, 0);
Dir = FakeFile->getDir();
}
@@ -1446,7 +1501,8 @@ bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem,
if (llvm::sys::path::filename(DirName) == "Modules") {
DirName = llvm::sys::path::parent_path(DirName);
if (DirName.endswith(".framework"))
- Dir = FileMgr.getDirectory(DirName);
+ if (auto DirOrErr = FileMgr.getDirectory(DirName))
+ Dir = *DirOrErr;
// FIXME: This assert can fail if there's a race between the above check
// and the removal of the directory.
assert(Dir && "parent must exist");
@@ -1503,13 +1559,15 @@ HeaderSearch::lookupModuleMapFile(const DirectoryEntry *Dir, bool IsFramework) {
if (IsFramework)
llvm::sys::path::append(ModuleMapFileName, "Modules");
llvm::sys::path::append(ModuleMapFileName, "module.modulemap");
- if (const FileEntry *F = FileMgr.getFile(ModuleMapFileName))
- return F;
+ if (auto F = FileMgr.getFile(ModuleMapFileName))
+ return *F;
// Continue to allow module.map
ModuleMapFileName = Dir->getName();
llvm::sys::path::append(ModuleMapFileName, "module.map");
- return FileMgr.getFile(ModuleMapFileName);
+ if (auto F = FileMgr.getFile(ModuleMapFileName))
+ return *F;
+ return nullptr;
}
Module *HeaderSearch::loadFrameworkModule(StringRef Name,
@@ -1540,8 +1598,8 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name,
HeaderSearch::LoadModuleMapResult
HeaderSearch::loadModuleMapFile(StringRef DirName, bool IsSystem,
bool IsFramework) {
- if (const DirectoryEntry *Dir = FileMgr.getDirectory(DirName))
- return loadModuleMapFile(Dir, IsSystem, IsFramework);
+ if (auto Dir = FileMgr.getDirectory(DirName))
+ return loadModuleMapFile(*Dir, IsSystem, IsFramework);
return LMM_NoDirectory;
}
@@ -1589,13 +1647,13 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
if (llvm::sys::path::extension(Dir->path()) != ".framework")
continue;
- const DirectoryEntry *FrameworkDir =
+ auto FrameworkDir =
FileMgr.getDirectory(Dir->path());
if (!FrameworkDir)
continue;
// Load this framework module.
- loadFrameworkModule(llvm::sys::path::stem(Dir->path()), FrameworkDir,
+ loadFrameworkModule(llvm::sys::path::stem(Dir->path()), *FrameworkDir,
IsSystem);
}
continue;
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index db53e6bec044..17f5ab1e035d 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -218,6 +218,15 @@ Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc,
return L;
}
+bool Lexer::skipOver(unsigned NumBytes) {
+ IsAtPhysicalStartOfLine = true;
+ IsAtStartOfLine = true;
+ if ((BufferPtr + NumBytes) > BufferEnd)
+ return true;
+ BufferPtr += NumBytes;
+ return false;
+}
+
template <typename T> static void StringifyImpl(T &Str, char Quote) {
typename T::size_type i = 0, e = Str.size();
while (i < e) {
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index 5aa4679fad46..7ede00b4aa64 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -76,8 +76,6 @@ MacroArgs *MacroArgs::create(const MacroInfo *MI,
/// destroy - Destroy and deallocate the memory for this object.
///
void MacroArgs::destroy(Preprocessor &PP) {
- StringifiedArgs.clear();
-
// Don't clear PreExpArgTokens, just clear the entries. Clearing the entries
// would deallocate the element vectors.
for (unsigned i = 0, e = PreExpArgTokens.size(); i != e; ++i)
@@ -307,21 +305,3 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
ExpansionLocStart, ExpansionLocEnd);
return Tok;
}
-
-/// getStringifiedArgument - Compute, cache, and return the specified argument
-/// that has been 'stringified' as required by the # operator.
-const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo,
- Preprocessor &PP,
- SourceLocation ExpansionLocStart,
- SourceLocation ExpansionLocEnd) {
- assert(ArgNo < getNumMacroArguments() && "Invalid argument number!");
- if (StringifiedArgs.empty())
- StringifiedArgs.resize(getNumMacroArguments(), {});
-
- if (StringifiedArgs[ArgNo].isNot(tok::string_literal))
- StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP,
- /*Charify=*/false,
- ExpansionLocStart,
- ExpansionLocEnd);
- return StringifiedArgs[ArgNo];
-}
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 5e0be1a57da4..db59629997ee 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -179,12 +179,12 @@ const FileEntry *ModuleMap::findHeader(
SmallString<128> FullPathName(Directory->getName());
auto GetFile = [&](StringRef Filename) -> const FileEntry * {
- auto *File = SourceMgr.getFileManager().getFile(Filename);
+ auto File = SourceMgr.getFileManager().getFile(Filename);
if (!File ||
- (Header.Size && File->getSize() != *Header.Size) ||
- (Header.ModTime && File->getModificationTime() != *Header.ModTime))
+ (Header.Size && (*File)->getSize() != *Header.Size) ||
+ (Header.ModTime && (*File)->getModificationTime() != *Header.ModTime))
return nullptr;
- return File;
+ return *File;
};
auto GetFrameworkFile = [&]() -> const FileEntry * {
@@ -300,12 +300,12 @@ bool ModuleMap::resolveAsBuiltinHeader(
// supplied by Clang. Find that builtin header.
SmallString<128> Path;
llvm::sys::path::append(Path, BuiltinIncludeDir->getName(), Header.FileName);
- auto *File = SourceMgr.getFileManager().getFile(Path);
+ auto File = SourceMgr.getFileManager().getFile(Path);
if (!File)
return false;
auto Role = headerKindToRole(Header.Kind);
- Module::Header H = {Path.str(), File};
+ Module::Header H = {Path.str(), *File};
addHeader(Mod, H, Role);
return true;
}
@@ -430,7 +430,10 @@ ModuleMap::findHeaderInUmbrellaDirs(const FileEntry *File,
break;
// Resolve the parent path to a directory entry.
- Dir = SourceMgr.getFileManager().getDirectory(DirName);
+ if (auto DirEntry = SourceMgr.getFileManager().getDirectory(DirName))
+ Dir = *DirEntry;
+ else
+ Dir = nullptr;
} while (Dir);
return {};
}
@@ -755,7 +758,10 @@ ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header,
break;
// Resolve the parent path to a directory entry.
- Dir = SourceMgr.getFileManager().getDirectory(DirName);
+ if (auto DirEntry = SourceMgr.getFileManager().getDirectory(DirName))
+ Dir = *DirEntry;
+ else
+ Dir = nullptr;
} while (Dir);
return false;
@@ -938,24 +944,24 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
if (llvm::sys::path::has_parent_path(FrameworkDirName)) {
// Figure out the parent path.
StringRef Parent = llvm::sys::path::parent_path(FrameworkDirName);
- if (const DirectoryEntry *ParentDir = FileMgr.getDirectory(Parent)) {
+ if (auto ParentDir = FileMgr.getDirectory(Parent)) {
// Check whether we have already looked into the parent directory
// for a module map.
llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::const_iterator
- inferred = InferredDirectories.find(ParentDir);
+ inferred = InferredDirectories.find(*ParentDir);
if (inferred == InferredDirectories.end()) {
// We haven't looked here before. Load a module map, if there is
// one.
bool IsFrameworkDir = Parent.endswith(".framework");
if (const FileEntry *ModMapFile =
- HeaderInfo.lookupModuleMapFile(ParentDir, IsFrameworkDir)) {
- parseModuleMapFile(ModMapFile, Attrs.IsSystem, ParentDir);
- inferred = InferredDirectories.find(ParentDir);
+ HeaderInfo.lookupModuleMapFile(*ParentDir, IsFrameworkDir)) {
+ parseModuleMapFile(ModMapFile, Attrs.IsSystem, *ParentDir);
+ inferred = InferredDirectories.find(*ParentDir);
}
if (inferred == InferredDirectories.end())
inferred = InferredDirectories.insert(
- std::make_pair(ParentDir, InferredDirectory())).first;
+ std::make_pair(*ParentDir, InferredDirectory())).first;
}
if (inferred->second.InferModules) {
@@ -986,7 +992,7 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
// Look for an umbrella header.
SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName());
llvm::sys::path::append(UmbrellaName, "Headers", ModuleName + ".h");
- const FileEntry *UmbrellaHeader = FileMgr.getFile(UmbrellaName);
+ auto 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
@@ -1016,7 +1022,7 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
//
// The "Headers/" component of the name is implied because this is
// a framework module.
- setUmbrellaHeader(Result, UmbrellaHeader, ModuleName + ".h");
+ setUmbrellaHeader(Result, *UmbrellaHeader, ModuleName + ".h");
// export *
Result->Exports.push_back(Module::ExportDecl(nullptr, true));
@@ -1039,13 +1045,14 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
if (!StringRef(Dir->path()).endswith(".framework"))
continue;
- if (const DirectoryEntry *SubframeworkDir =
+ if (auto SubframeworkDir =
FileMgr.getDirectory(Dir->path())) {
// Note: as an egregious but useful hack, we use the real path here and
// check whether it is actually a subdirectory of the parent directory.
// This will not be the case if the 'subframework' is actually a symlink
// out to a top-level framework.
- StringRef SubframeworkDirName = FileMgr.getCanonicalName(SubframeworkDir);
+ StringRef SubframeworkDirName =
+ FileMgr.getCanonicalName(*SubframeworkDir);
bool FoundParent = false;
do {
// Get the parent directory name.
@@ -1054,9 +1061,11 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
if (SubframeworkDirName.empty())
break;
- if (FileMgr.getDirectory(SubframeworkDirName) == FrameworkDir) {
- FoundParent = true;
- break;
+ if (auto SubDir = FileMgr.getDirectory(SubframeworkDirName)) {
+ if (*SubDir == FrameworkDir) {
+ FoundParent = true;
+ break;
+ }
}
} while (true);
@@ -1064,7 +1073,7 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir,
continue;
// FIXME: Do we want to warn about subframeworks without umbrella headers?
- inferFrameworkModule(SubframeworkDir, Attrs, Result);
+ inferFrameworkModule(*SubframeworkDir, Attrs, Result);
}
}
@@ -2130,12 +2139,12 @@ void ModuleMapParser::parseExternModuleDecl() {
llvm::sys::path::append(ModuleMapFileName, FileName);
FileNameRef = ModuleMapFileName;
}
- if (const FileEntry *File = SourceMgr.getFileManager().getFile(FileNameRef))
+ if (auto File = SourceMgr.getFileManager().getFile(FileNameRef))
Map.parseModuleMapFile(
- File, /*IsSystem=*/false,
+ *File, /*IsSystem=*/false,
Map.HeaderInfo.getHeaderSearchOpts().ModuleMapFileHomeIsCwd
? Directory
- : File->getDir(),
+ : (*File)->getDir(),
FileID(), nullptr, ExternLoc);
}
@@ -2384,13 +2393,15 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
// Look for this file.
const DirectoryEntry *Dir = nullptr;
- if (llvm::sys::path::is_absolute(DirName))
- Dir = SourceMgr.getFileManager().getDirectory(DirName);
- else {
+ if (llvm::sys::path::is_absolute(DirName)) {
+ if (auto D = SourceMgr.getFileManager().getDirectory(DirName))
+ Dir = *D;
+ } else {
SmallString<128> PathName;
PathName = Directory->getName();
llvm::sys::path::append(PathName, DirName);
- Dir = SourceMgr.getFileManager().getDirectory(PathName);
+ if (auto D = SourceMgr.getFileManager().getDirectory(PathName))
+ Dir = *D;
}
if (!Dir) {
@@ -2410,9 +2421,9 @@ void ModuleMapParser::parseUmbrellaDirDecl(SourceLocation UmbrellaLoc) {
SourceMgr.getFileManager().getVirtualFileSystem();
for (llvm::vfs::recursive_directory_iterator I(FS, Dir->getName(), EC), E;
I != E && !EC; I.increment(EC)) {
- if (const FileEntry *FE = SourceMgr.getFileManager().getFile(I->path())) {
+ if (auto FE = SourceMgr.getFileManager().getFile(I->path())) {
- Module::Header Header = {I->path(), FE};
+ Module::Header Header = {I->path(), *FE};
Headers.push_back(std::move(Header));
}
}
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 2756042f23eb..3b7eaee3c914 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -33,6 +33,7 @@
#include "clang/Lex/Token.h"
#include "clang/Lex/VariadicMacroSupport.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/STLExtras.h"
@@ -369,6 +370,37 @@ SourceLocation Preprocessor::CheckEndOfDirective(const char *DirType,
return DiscardUntilEndOfDirective().getEnd();
}
+Optional<unsigned> Preprocessor::getSkippedRangeForExcludedConditionalBlock(
+ SourceLocation HashLoc) {
+ if (!ExcludedConditionalDirectiveSkipMappings)
+ return None;
+ if (!HashLoc.isFileID())
+ return None;
+
+ std::pair<FileID, unsigned> HashFileOffset =
+ SourceMgr.getDecomposedLoc(HashLoc);
+ const llvm::MemoryBuffer *Buf = SourceMgr.getBuffer(HashFileOffset.first);
+ auto It = ExcludedConditionalDirectiveSkipMappings->find(Buf);
+ if (It == ExcludedConditionalDirectiveSkipMappings->end())
+ return None;
+
+ const PreprocessorSkippedRangeMapping &SkippedRanges = *It->getSecond();
+ // Check if the offset of '#' is mapped in the skipped ranges.
+ auto MappingIt = SkippedRanges.find(HashFileOffset.second);
+ if (MappingIt == SkippedRanges.end())
+ return None;
+
+ unsigned BytesToSkip = MappingIt->getSecond();
+ unsigned CurLexerBufferOffset = CurLexer->getCurrentBufferOffset();
+ assert(CurLexerBufferOffset >= HashFileOffset.second &&
+ "lexer is before the hash?");
+ // Take into account the fact that the lexer has already advanced, so the
+ // number of bytes to skip must be adjusted.
+ unsigned LengthDiff = CurLexerBufferOffset - HashFileOffset.second;
+ assert(BytesToSkip >= LengthDiff && "lexer is after the skipped range?");
+ return BytesToSkip - LengthDiff;
+}
+
/// SkipExcludedConditionalBlock - We just read a \#if or related directive and
/// decided that the subsequent tokens are in the \#if'd out portion of the
/// file. Lex the rest of the file, until we see an \#endif. If
@@ -395,6 +427,11 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
// disabling warnings, etc.
CurPPLexer->LexingRawMode = true;
Token Tok;
+ if (auto SkipLength =
+ getSkippedRangeForExcludedConditionalBlock(HashTokenLoc)) {
+ // Skip to the next '#endif' / '#else' / '#elif'.
+ CurLexer->skipOver(*SkipLength);
+ }
while (true) {
CurLexer->Lex(Tok);
@@ -678,7 +715,7 @@ Preprocessor::getModuleHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
return nullptr;
}
-const FileEntry *Preprocessor::LookupFile(
+Optional<FileEntryRef> Preprocessor::LookupFile(
SourceLocation FilenameLoc, StringRef Filename, bool isAngled,
const DirectoryLookup *FromDir, const FileEntry *FromFile,
const DirectoryLookup *&CurDir, SmallVectorImpl<char> *SearchPath,
@@ -715,7 +752,7 @@ const FileEntry *Preprocessor::LookupFile(
BuildSystemModule = getCurrentModule()->IsSystem;
} else if ((FileEnt =
SourceMgr.getFileEntryForID(SourceMgr.getMainFileID())))
- Includers.push_back(std::make_pair(FileEnt, FileMgr.getDirectory(".")));
+ Includers.push_back(std::make_pair(FileEnt, *FileMgr.getDirectory(".")));
} else {
Includers.push_back(std::make_pair(FileEnt, FileEnt->getDir()));
}
@@ -739,7 +776,7 @@ const FileEntry *Preprocessor::LookupFile(
// the include path until we find that file or run out of files.
const DirectoryLookup *TmpCurDir = CurDir;
const DirectoryLookup *TmpFromDir = nullptr;
- while (const FileEntry *FE = HeaderInfo.LookupFile(
+ while (Optional<FileEntryRef> FE = HeaderInfo.LookupFile(
Filename, FilenameLoc, isAngled, TmpFromDir, TmpCurDir,
Includers, SearchPath, RelativePath, RequestingModule,
SuggestedModule, /*IsMapped=*/nullptr,
@@ -747,7 +784,7 @@ const FileEntry *Preprocessor::LookupFile(
// Keep looking as if this file did a #include_next.
TmpFromDir = TmpCurDir;
++TmpFromDir;
- if (FE == FromFile) {
+ if (&FE->getFileEntry() == FromFile) {
// Found it.
FromDir = TmpFromDir;
CurDir = TmpCurDir;
@@ -757,7 +794,7 @@ const FileEntry *Preprocessor::LookupFile(
}
// Do a standard file entry lookup.
- const FileEntry *FE = HeaderInfo.LookupFile(
+ Optional<FileEntryRef> FE = HeaderInfo.LookupFile(
Filename, FilenameLoc, isAngled, FromDir, CurDir, Includers, SearchPath,
RelativePath, RequestingModule, SuggestedModule, IsMapped,
IsFrameworkFound, SkipCache, BuildSystemModule);
@@ -765,7 +802,7 @@ const FileEntry *Preprocessor::LookupFile(
if (SuggestedModule && !LangOpts.AsmPreprocessor)
HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
RequestingModule, RequestingModuleIsModuleInterface, FilenameLoc,
- Filename, FE);
+ Filename, &FE->getFileEntry());
return FE;
}
@@ -775,14 +812,13 @@ const FileEntry *Preprocessor::LookupFile(
// headers on the #include stack and pass them to HeaderInfo.
if (IsFileLexer()) {
if ((CurFileEnt = CurPPLexer->getFileEntry())) {
- if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt,
- SearchPath, RelativePath,
- RequestingModule,
- SuggestedModule))) {
+ if (Optional<FileEntryRef> FE = HeaderInfo.LookupSubframeworkHeader(
+ Filename, CurFileEnt, SearchPath, RelativePath, RequestingModule,
+ SuggestedModule)) {
if (SuggestedModule && !LangOpts.AsmPreprocessor)
HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
RequestingModule, RequestingModuleIsModuleInterface, FilenameLoc,
- Filename, FE);
+ Filename, &FE->getFileEntry());
return FE;
}
}
@@ -791,13 +827,13 @@ const FileEntry *Preprocessor::LookupFile(
for (IncludeStackInfo &ISEntry : llvm::reverse(IncludeMacroStack)) {
if (IsFileLexer(ISEntry)) {
if ((CurFileEnt = ISEntry.ThePPLexer->getFileEntry())) {
- if ((FE = HeaderInfo.LookupSubframeworkHeader(
+ if (Optional<FileEntryRef> FE = HeaderInfo.LookupSubframeworkHeader(
Filename, CurFileEnt, SearchPath, RelativePath,
- RequestingModule, SuggestedModule))) {
+ RequestingModule, SuggestedModule)) {
if (SuggestedModule && !LangOpts.AsmPreprocessor)
HeaderInfo.getModuleMap().diagnoseHeaderInclusion(
RequestingModule, RequestingModuleIsModuleInterface,
- FilenameLoc, Filename, FE);
+ FilenameLoc, Filename, &FE->getFileEntry());
return FE;
}
}
@@ -805,7 +841,7 @@ const FileEntry *Preprocessor::LookupFile(
}
// Otherwise, we really couldn't find the file.
- return nullptr;
+ return None;
}
//===----------------------------------------------------------------------===//
@@ -1022,7 +1058,7 @@ void Preprocessor::HandleDirective(Token &Result) {
// various pseudo-ops. Just return the # token and push back the following
// token to be lexed next time.
if (getLangOpts().AsmPreprocessor) {
- auto Toks = llvm::make_unique<Token[]>(2);
+ auto Toks = std::make_unique<Token[]>(2);
// Return the # and the token after it.
Toks[0] = SavedHash;
Toks[1] = Result;
@@ -1512,7 +1548,7 @@ void Preprocessor::EnterAnnotationToken(SourceRange Range,
void *AnnotationVal) {
// FIXME: Produce this as the current token directly, rather than
// allocating a new token for it.
- auto Tok = llvm::make_unique<Token[]>(1);
+ auto Tok = std::make_unique<Token[]>(1);
Tok[0].startToken();
Tok[0].setKind(Kind);
Tok[0].setLocation(Range.getBegin());
@@ -1675,6 +1711,133 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
}
}
+Optional<FileEntryRef> Preprocessor::LookupHeaderIncludeOrImport(
+ const DirectoryLookup *&CurDir, StringRef Filename,
+ SourceLocation FilenameLoc, CharSourceRange FilenameRange,
+ const Token &FilenameTok, bool &IsFrameworkFound, bool IsImportDecl,
+ bool &IsMapped, const DirectoryLookup *LookupFrom,
+ const FileEntry *LookupFromFile, StringRef LookupFilename,
+ SmallVectorImpl<char> &RelativePath, SmallVectorImpl<char> &SearchPath,
+ ModuleMap::KnownHeader &SuggestedModule, bool isAngled) {
+ Optional<FileEntryRef> File = LookupFile(
+ FilenameLoc, LookupFilename,
+ isAngled, LookupFrom, LookupFromFile, CurDir,
+ Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
+ &SuggestedModule, &IsMapped, &IsFrameworkFound);
+ if (File)
+ return File;
+
+ if (Callbacks) {
+ // Give the clients a chance to recover.
+ SmallString<128> RecoveryPath;
+ if (Callbacks->FileNotFound(Filename, RecoveryPath)) {
+ if (auto DE = FileMgr.getOptionalDirectoryRef(RecoveryPath)) {
+ // Add the recovery path to the list of search paths.
+ DirectoryLookup DL(*DE, SrcMgr::C_User, false);
+ HeaderInfo.AddSearchPath(DL, isAngled);
+
+ // Try the lookup again, skipping the cache.
+ Optional<FileEntryRef> File = LookupFile(
+ FilenameLoc,
+ LookupFilename, isAngled,
+ LookupFrom, LookupFromFile, CurDir, nullptr, nullptr,
+ &SuggestedModule, &IsMapped, /*IsFrameworkFound=*/nullptr,
+ /*SkipCache*/ true);
+ if (File)
+ return File;
+ }
+ }
+ }
+
+ if (SuppressIncludeNotFoundError)
+ return None;
+
+ // If the file could not be located and it was included via angle
+ // brackets, we can attempt a lookup as though it were a quoted path to
+ // provide the user with a possible fixit.
+ if (isAngled) {
+ Optional<FileEntryRef> File = LookupFile(
+ FilenameLoc, LookupFilename,
+ false, LookupFrom, LookupFromFile, CurDir,
+ Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
+ &SuggestedModule, &IsMapped,
+ /*IsFrameworkFound=*/nullptr);
+ if (File) {
+ Diag(FilenameTok, diag::err_pp_file_not_found_angled_include_not_fatal)
+ << Filename << IsImportDecl
+ << FixItHint::CreateReplacement(FilenameRange,
+ "\"" + Filename.str() + "\"");
+ return File;
+ }
+ }
+
+ // Check for likely typos due to leading or trailing non-isAlphanumeric
+ // characters
+ StringRef OriginalFilename = Filename;
+ if (LangOpts.SpellChecking) {
+ // A heuristic to correct a typo file name by removing leading and
+ // trailing non-isAlphanumeric characters.
+ auto CorrectTypoFilename = [](llvm::StringRef Filename) {
+ Filename = Filename.drop_until(isAlphanumeric);
+ while (!Filename.empty() && !isAlphanumeric(Filename.back())) {
+ Filename = Filename.drop_back();
+ }
+ return Filename;
+ };
+ StringRef TypoCorrectionName = CorrectTypoFilename(Filename);
+
+#ifndef _WIN32
+ // Normalize slashes when compiling with -fms-extensions on non-Windows.
+ // This is unnecessary on Windows since the filesystem there handles
+ // backslashes.
+ SmallString<128> NormalizedTypoCorrectionPath;
+ if (LangOpts.MicrosoftExt) {
+ NormalizedTypoCorrectionPath = TypoCorrectionName;
+ llvm::sys::path::native(NormalizedTypoCorrectionPath);
+ TypoCorrectionName = NormalizedTypoCorrectionPath;
+ }
+#endif
+
+ Optional<FileEntryRef> File = LookupFile(
+ FilenameLoc, TypoCorrectionName, isAngled, LookupFrom, LookupFromFile,
+ CurDir, Callbacks ? &SearchPath : nullptr,
+ Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped,
+ /*IsFrameworkFound=*/nullptr);
+ if (File) {
+ auto Hint =
+ isAngled ? FixItHint::CreateReplacement(
+ FilenameRange, "<" + TypoCorrectionName.str() + ">")
+ : FixItHint::CreateReplacement(
+ FilenameRange, "\"" + TypoCorrectionName.str() + "\"");
+ Diag(FilenameTok, diag::err_pp_file_not_found_typo_not_fatal)
+ << OriginalFilename << TypoCorrectionName << Hint;
+ // We found the file, so set the Filename to the name after typo
+ // correction.
+ Filename = TypoCorrectionName;
+ return File;
+ }
+ }
+
+ // If the file is still not found, just go with the vanilla diagnostic
+ assert(!File.hasValue() && "expected missing file");
+ Diag(FilenameTok, diag::err_pp_file_not_found)
+ << OriginalFilename << FilenameRange;
+ if (IsFrameworkFound) {
+ size_t SlashPos = OriginalFilename.find('/');
+ assert(SlashPos != StringRef::npos &&
+ "Include with framework name should have '/' in the filename");
+ StringRef FrameworkName = OriginalFilename.substr(0, SlashPos);
+ FrameworkCacheEntry &CacheEntry =
+ HeaderInfo.LookupFrameworkCache(FrameworkName);
+ assert(CacheEntry.Directory && "Found framework should be in cache");
+ Diag(FilenameTok, diag::note_pp_framework_without_header)
+ << OriginalFilename.substr(SlashPos + 1) << FrameworkName
+ << CacheEntry.Directory->getName();
+ }
+
+ return None;
+}
+
/// Handle either a #include-like directive or an import declaration that names
/// a header file.
///
@@ -1710,12 +1873,12 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
SourceLocation StartLoc = IsImportDecl ? IncludeTok.getLocation() : HashLoc;
// Complain about attempts to #include files in an audit pragma.
- if (PragmaARCCFCodeAuditedLoc.isValid()) {
+ if (PragmaARCCFCodeAuditedInfo.second.isValid()) {
Diag(StartLoc, diag::err_pp_include_in_arc_cf_code_audited) << IsImportDecl;
- Diag(PragmaARCCFCodeAuditedLoc, diag::note_pragma_entered_here);
+ Diag(PragmaARCCFCodeAuditedInfo.second, diag::note_pragma_entered_here);
// Immediately leave the pragma.
- PragmaARCCFCodeAuditedLoc = SourceLocation();
+ PragmaARCCFCodeAuditedInfo = {nullptr, SourceLocation()};
}
// Complain about attempts to #include files in an assume-nonnull pragma.
@@ -1746,127 +1909,26 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// the path.
ModuleMap::KnownHeader SuggestedModule;
SourceLocation FilenameLoc = FilenameTok.getLocation();
+ StringRef LookupFilename = Filename;
+
+#ifndef _WIN32
+ // Normalize slashes when compiling with -fms-extensions on non-Windows. This
+ // is unnecessary on Windows since the filesystem there handles backslashes.
SmallString<128> NormalizedPath;
- if (LangOpts.MSVCCompat) {
+ if (LangOpts.MicrosoftExt) {
NormalizedPath = Filename.str();
-#ifndef _WIN32
llvm::sys::path::native(NormalizedPath);
-#endif
+ LookupFilename = NormalizedPath;
}
- const FileEntry *File = LookupFile(
- FilenameLoc, LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename,
- isAngled, LookupFrom, LookupFromFile, CurDir,
- Callbacks ? &SearchPath : nullptr, Callbacks ? &RelativePath : nullptr,
- &SuggestedModule, &IsMapped, &IsFrameworkFound);
-
- if (!File) {
- if (Callbacks) {
- // 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, false);
- HeaderInfo.AddSearchPath(DL, isAngled);
-
- // Try the lookup again, skipping the cache.
- File = LookupFile(
- FilenameLoc,
- LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled,
- LookupFrom, LookupFromFile, CurDir, nullptr, nullptr,
- &SuggestedModule, &IsMapped, /*IsFrameworkFound=*/nullptr,
- /*SkipCache*/ true);
- }
- }
- }
-
- if (!SuppressIncludeNotFoundError) {
- // If the file could not be located and it was included via angle
- // brackets, we can attempt a lookup as though it were a quoted path to
- // provide the user with a possible fixit.
- if (isAngled) {
- File = LookupFile(
- FilenameLoc,
- LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, false,
- LookupFrom, LookupFromFile, CurDir,
- Callbacks ? &SearchPath : nullptr,
- Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped,
- /*IsFrameworkFound=*/nullptr);
- if (File) {
- Diag(FilenameTok,
- diag::err_pp_file_not_found_angled_include_not_fatal)
- << Filename << IsImportDecl
- << FixItHint::CreateReplacement(FilenameRange,
- "\"" + Filename.str() + "\"");
- }
- }
-
- // Check for likely typos due to leading or trailing non-isAlphanumeric
- // characters
- StringRef OriginalFilename = Filename;
- if (LangOpts.SpellChecking && !File) {
- // A heuristic to correct a typo file name by removing leading and
- // trailing non-isAlphanumeric characters.
- auto CorrectTypoFilename = [](llvm::StringRef Filename) {
- Filename = Filename.drop_until(isAlphanumeric);
- while (!Filename.empty() && !isAlphanumeric(Filename.back())) {
- Filename = Filename.drop_back();
- }
- return Filename;
- };
- StringRef TypoCorrectionName = CorrectTypoFilename(Filename);
- SmallString<128> NormalizedTypoCorrectionPath;
- if (LangOpts.MSVCCompat) {
- NormalizedTypoCorrectionPath = TypoCorrectionName.str();
-#ifndef _WIN32
- llvm::sys::path::native(NormalizedTypoCorrectionPath);
#endif
- }
- File = LookupFile(
- FilenameLoc,
- LangOpts.MSVCCompat ? NormalizedTypoCorrectionPath.c_str()
- : TypoCorrectionName,
- isAngled, LookupFrom, LookupFromFile, CurDir,
- Callbacks ? &SearchPath : nullptr,
- Callbacks ? &RelativePath : nullptr, &SuggestedModule, &IsMapped,
- /*IsFrameworkFound=*/nullptr);
- if (File) {
- auto Hint =
- isAngled
- ? FixItHint::CreateReplacement(
- FilenameRange, "<" + TypoCorrectionName.str() + ">")
- : FixItHint::CreateReplacement(
- FilenameRange, "\"" + TypoCorrectionName.str() + "\"");
- Diag(FilenameTok, diag::err_pp_file_not_found_typo_not_fatal)
- << OriginalFilename << TypoCorrectionName << Hint;
- // We found the file, so set the Filename to the name after typo
- // correction.
- Filename = TypoCorrectionName;
- }
- }
- // If the file is still not found, just go with the vanilla diagnostic
- if (!File) {
- Diag(FilenameTok, diag::err_pp_file_not_found) << OriginalFilename
- << FilenameRange;
- if (IsFrameworkFound) {
- size_t SlashPos = OriginalFilename.find('/');
- assert(SlashPos != StringRef::npos &&
- "Include with framework name should have '/' in the filename");
- StringRef FrameworkName = OriginalFilename.substr(0, SlashPos);
- FrameworkCacheEntry &CacheEntry =
- HeaderInfo.LookupFrameworkCache(FrameworkName);
- assert(CacheEntry.Directory && "Found framework should be in cache");
- Diag(FilenameTok, diag::note_pp_framework_without_header)
- << OriginalFilename.substr(SlashPos + 1) << FrameworkName
- << CacheEntry.Directory->getName();
- }
- }
- }
- }
+ Optional<FileEntryRef> File = LookupHeaderIncludeOrImport(
+ CurDir, Filename, FilenameLoc, FilenameRange, FilenameTok,
+ IsFrameworkFound, IsImportDecl, IsMapped, LookupFrom, LookupFromFile,
+ LookupFilename, RelativePath, SearchPath, SuggestedModule, isAngled);
if (usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader) {
- if (isPCHThroughHeader(File))
+ if (File && isPCHThroughHeader(&File->getFileEntry()))
SkippingUntilPCHThroughHeader = false;
return {ImportAction::None};
}
@@ -1877,7 +1939,8 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// some directives (e.g. #endif of a header guard) will never be seen.
// Since this will lead to confusing errors, avoid the inclusion.
if (File && PreambleConditionalStack.isRecording() &&
- SourceMgr.translateFile(File) == SourceMgr.getMainFileID()) {
+ SourceMgr.translateFile(&File->getFileEntry()) ==
+ SourceMgr.getMainFileID()) {
Diag(FilenameTok.getLocation(),
diag::err_pp_including_mainfile_in_preamble);
return {ImportAction::None};
@@ -1896,7 +1959,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// include cycle. Don't enter already processed files again as it can lead to
// reaching the max allowed include depth again.
if (Action == Enter && HasReachedMaxIncludeDepth && File &&
- HeaderInfo.getFileInfo(File).NumIncludes)
+ HeaderInfo.getFileInfo(&File->getFileEntry()).NumIncludes)
Action = IncludeLimitReached;
// Determine whether we should try to import the module for this #include, if
@@ -1972,7 +2035,8 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
SrcMgr::CharacteristicKind FileCharacter =
SourceMgr.getFileCharacteristic(FilenameTok.getLocation());
if (File)
- FileCharacter = std::max(HeaderInfo.getFileDirFlavor(File), FileCharacter);
+ FileCharacter = std::max(HeaderInfo.getFileDirFlavor(&File->getFileEntry()),
+ FileCharacter);
// If this is a '#import' or an import-declaration, don't re-enter the file.
//
@@ -1986,8 +2050,8 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// Ask HeaderInfo if we should enter this #include file. If not, #including
// this file will have no effect.
if (Action == Enter && File &&
- !HeaderInfo.ShouldEnterIncludeFile(*this, File, EnterOnce,
- getLangOpts().Modules,
+ !HeaderInfo.ShouldEnterIncludeFile(*this, &File->getFileEntry(),
+ EnterOnce, getLangOpts().Modules,
SuggestedModule.getModule())) {
// Even if we've already preprocessed this header once and know that we
// don't need to see its contents again, we still need to import it if it's
@@ -2003,12 +2067,11 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// Notify the callback object that we've seen an inclusion directive.
// FIXME: Use a different callback for a pp-import?
Callbacks->InclusionDirective(
- HashLoc, IncludeTok,
- LangOpts.MSVCCompat ? NormalizedPath.c_str() : Filename, isAngled,
- FilenameRange, File, SearchPath, RelativePath,
+ HashLoc, IncludeTok, LookupFilename, isAngled, FilenameRange,
+ File ? &File->getFileEntry() : nullptr, SearchPath, RelativePath,
Action == Import ? SuggestedModule.getModule() : nullptr,
FileCharacter);
- if (Action == Skip)
+ if (Action == Skip && File)
Callbacks->FileSkipped(*File, FilenameTok, FileCharacter);
}
@@ -2026,11 +2089,11 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// Issue a diagnostic if the name of the file on disk has a different case
// than the one we're about to open.
const bool CheckIncludePathPortability =
- !IsMapped && File && !File->tryGetRealPathName().empty();
+ !IsMapped && !File->getFileEntry().tryGetRealPathName().empty();
if (CheckIncludePathPortability) {
- StringRef Name = LangOpts.MSVCCompat ? NormalizedPath.str() : Filename;
- StringRef RealPathName = File->tryGetRealPathName();
+ StringRef Name = LookupFilename;
+ StringRef RealPathName = File->getFileEntry().tryGetRealPathName();
SmallVector<StringRef, 16> Components(llvm::sys::path::begin(Name),
llvm::sys::path::end(Name));
@@ -2101,7 +2164,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// position on the file where it will be included and after the expansions.
if (IncludePos.isMacroID())
IncludePos = SourceMgr.getExpansionRange(IncludePos).getEnd();
- FileID FID = SourceMgr.createFileID(File, IncludePos, FileCharacter);
+ FileID FID = SourceMgr.createFileID(*File, IncludePos, FileCharacter);
assert(FID.isValid() && "Expected valid file ID");
// If all is good, enter the new file!
@@ -2399,6 +2462,13 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody(
Token Tok;
LexUnexpandedToken(Tok);
+ // Ensure we consume the rest of the macro body if errors occur.
+ auto _ = llvm::make_scope_exit([&]() {
+ // The flag indicates if we are still waiting for 'eod'.
+ if (CurLexer->ParsingPreprocessorDirective)
+ DiscardUntilEndOfDirective();
+ });
+
// Used to un-poison and then re-poison identifiers of the __VA_ARGS__ ilk
// within their appropriate context.
VariadicMacroScopeGuard VariadicMacroScopeGuard(*this);
@@ -2420,12 +2490,8 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody(
} else if (Tok.is(tok::l_paren)) {
// This is a function-like macro definition. Read the argument list.
MI->setIsFunctionLike();
- if (ReadMacroParameterList(MI, LastTok)) {
- // Throw away the rest of the line.
- if (CurPPLexer->ParsingPreprocessorDirective)
- DiscardUntilEndOfDirective();
+ if (ReadMacroParameterList(MI, LastTok))
return nullptr;
- }
// If this is a definition of an ISO C/C++ variadic function-like macro (not
// using the GNU named varargs extension) inform our variadic scope guard
@@ -2723,7 +2789,8 @@ void Preprocessor::HandleDefineDirective(
// If we need warning for not using the macro, add its location in the
// warn-because-unused-macro set. If it gets used it will be removed from set.
if (getSourceManager().isInMainFile(MI->getDefinitionLoc()) &&
- !Diags->isIgnored(diag::pp_macro_not_used, MI->getDefinitionLoc())) {
+ !Diags->isIgnored(diag::pp_macro_not_used, MI->getDefinitionLoc()) &&
+ !MacroExpansionInDirectivesOverride) {
MI->setIsWarnIfUnused(true);
WarnUnusedMacroLocs.insert(MI->getDefinitionLoc());
}
@@ -2832,6 +2899,9 @@ void Preprocessor::HandleIfdefDirective(Token &Result,
Callbacks->Ifdef(DirectiveTok.getLocation(), MacroNameTok, MD);
}
+ bool RetainExcludedCB = PPOpts->RetainExcludedConditionalBlocks &&
+ getSourceManager().isInMainFile(DirectiveTok.getLocation());
+
// Should we include the stuff contained by this directive?
if (PPOpts->SingleFileParseMode && !MI) {
// In 'single-file-parse mode' undefined identifiers trigger parsing of all
@@ -2839,7 +2909,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result,
CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(),
/*wasskip*/false, /*foundnonskip*/false,
/*foundelse*/false);
- } else if (!MI == isIfndef) {
+ } else if (!MI == isIfndef || RetainExcludedCB) {
// Yes, remember that we are inside a conditional, then lex the next token.
CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(),
/*wasskip*/false, /*foundnonskip*/true,
@@ -2880,13 +2950,16 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
IfToken.getLocation(), DER.ExprRange,
(ConditionalTrue ? PPCallbacks::CVK_True : PPCallbacks::CVK_False));
+ bool RetainExcludedCB = PPOpts->RetainExcludedConditionalBlocks &&
+ getSourceManager().isInMainFile(IfToken.getLocation());
+
// Should we include the stuff contained by this directive?
if (PPOpts->SingleFileParseMode && DER.IncludedUndefinedIds) {
// In 'single-file-parse mode' undefined identifiers trigger parsing of all
// the directive blocks.
CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false,
/*foundnonskip*/false, /*foundelse*/false);
- } else if (ConditionalTrue) {
+ } else if (ConditionalTrue || RetainExcludedCB) {
// Yes, remember that we are inside a conditional, then lex the next token.
CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false,
/*foundnonskip*/true, /*foundelse*/false);
@@ -2948,7 +3021,10 @@ void Preprocessor::HandleElseDirective(Token &Result, const Token &HashToken) {
if (Callbacks)
Callbacks->Else(Result.getLocation(), CI.IfLoc);
- if (PPOpts->SingleFileParseMode && !CI.FoundNonSkip) {
+ bool RetainExcludedCB = PPOpts->RetainExcludedConditionalBlocks &&
+ getSourceManager().isInMainFile(Result.getLocation());
+
+ if ((PPOpts->SingleFileParseMode && !CI.FoundNonSkip) || RetainExcludedCB) {
// In 'single-file-parse mode' undefined identifiers trigger parsing of all
// the directive blocks.
CurPPLexer->pushConditionalLevel(CI.IfLoc, /*wasskip*/false,
@@ -2990,7 +3066,10 @@ void Preprocessor::HandleElifDirective(Token &ElifToken,
Callbacks->Elif(ElifToken.getLocation(), ConditionRange,
PPCallbacks::CVK_NotEvaluated, CI.IfLoc);
- if (PPOpts->SingleFileParseMode && !CI.FoundNonSkip) {
+ bool RetainExcludedCB = PPOpts->RetainExcludedConditionalBlocks &&
+ getSourceManager().isInMainFile(ElifToken.getLocation());
+
+ if ((PPOpts->SingleFileParseMode && !CI.FoundNonSkip) || RetainExcludedCB) {
// In 'single-file-parse mode' undefined identifiers trigger parsing of all
// the directive blocks.
CurPPLexer->pushConditionalLevel(ElifToken.getLocation(), /*wasskip*/false,
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index 7cce5f9c9fe4..802172693960 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -128,7 +128,7 @@ void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd,
MacroInfo *Macro, MacroArgs *Args) {
std::unique_ptr<TokenLexer> TokLexer;
if (NumCachedTokenLexers == 0) {
- TokLexer = llvm::make_unique<TokenLexer>(Tok, ILEnd, Macro, Args, *this);
+ TokLexer = std::make_unique<TokenLexer>(Tok, ILEnd, Macro, Args, *this);
} else {
TokLexer = std::move(TokenLexerCache[--NumCachedTokenLexers]);
TokLexer->Init(Tok, ILEnd, Macro, Args);
@@ -180,7 +180,7 @@ void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks,
// Create a macro expander to expand from the specified token stream.
std::unique_ptr<TokenLexer> TokLexer;
if (NumCachedTokenLexers == 0) {
- TokLexer = llvm::make_unique<TokenLexer>(
+ TokLexer = std::make_unique<TokenLexer>(
Toks, NumToks, DisableMacroExpansion, OwnsTokens, IsReinject, *this);
} else {
TokLexer = std::move(TokenLexerCache[--NumCachedTokenLexers]);
@@ -206,8 +206,8 @@ static void computeRelativePath(FileManager &FM, const DirectoryEntry *Dir,
StringRef FilePath = File->getDir()->getName();
StringRef Path = FilePath;
while (!Path.empty()) {
- if (const DirectoryEntry *CurDir = FM.getDirectory(Path)) {
- if (CurDir == Dir) {
+ if (auto CurDir = FM.getDirectory(Path)) {
+ if (*CurDir == Dir) {
Result = FilePath.substr(Path.size());
llvm::sys::path::append(Result,
llvm::sys::path::filename(File->getName()));
@@ -287,12 +287,12 @@ void Preprocessor::diagnoseMissingHeaderInUmbrellaDir(const Module &Mod) {
.Default(false))
continue;
- if (const FileEntry *Header = getFileManager().getFile(Entry->path()))
- if (!getSourceManager().hasFileInfo(Header)) {
- if (!ModMap.isHeaderInUnavailableModule(Header)) {
+ if (auto 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);
+ computeRelativePath(FileMgr, Dir, *Header, RelativePath);
Diag(StartLoc, diag::warn_uncovered_module_header)
<< Mod.getFullModuleName() << RelativePath;
}
@@ -376,12 +376,13 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
// 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);
+ if (PragmaARCCFCodeAuditedInfo.second.isValid() && !isEndOfMacro &&
+ !(CurLexer && CurLexer->Is_PragmaLexer)) {
+ Diag(PragmaARCCFCodeAuditedInfo.second,
+ diag::err_pp_eof_in_arc_cf_code_audited);
// Recover by leaving immediately.
- PragmaARCCFCodeAuditedLoc = SourceLocation();
+ PragmaARCCFCodeAuditedInfo = {nullptr, SourceLocation()};
}
// Complain about reaching a true EOF within assume_nonnull.
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 687b9a9d3b7b..dfbcaedcacff 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -804,7 +804,7 @@ MacroArgs *Preprocessor::ReadMacroCallArgumentList(Token &MacroName,
return nullptr;
}
// Do not lose the EOF/EOD.
- auto Toks = llvm::make_unique<Token[]>(1);
+ auto Toks = std::make_unique<Token[]>(1);
Toks[0] = Tok;
EnterTokenStream(std::move(Toks), 1, true, /*IsReinject*/ false);
break;
@@ -1210,19 +1210,20 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
// Search include directories.
const DirectoryLookup *CurDir;
- const FileEntry *File =
+ Optional<FileEntryRef> File =
PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, LookupFromFile,
CurDir, nullptr, nullptr, nullptr, nullptr, nullptr);
if (PPCallbacks *Callbacks = PP.getPPCallbacks()) {
SrcMgr::CharacteristicKind FileType = SrcMgr::C_User;
if (File)
- FileType = PP.getHeaderSearchInfo().getFileDirFlavor(File);
+ FileType =
+ PP.getHeaderSearchInfo().getFileDirFlavor(&File->getFileEntry());
Callbacks->HasInclude(FilenameLoc, Filename, isAngled, File, FileType);
}
// Get the result value. A result of true means the file exists.
- return File != nullptr;
+ return File.hasValue();
}
/// EvaluateHasInclude - Process a '__has_include("path")' expression.
@@ -1617,21 +1618,38 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
return true;
}
return true;
+ } else if (II->getTokenID() != tok::identifier ||
+ II->hasRevertedTokenIDToIdentifier()) {
+ // Treat all keywords that introduce a custom syntax of the form
+ //
+ // '__some_keyword' '(' [...] ')'
+ //
+ // as being "builtin functions", even if the syntax isn't a valid
+ // function call (for example, because the builtin takes a type
+ // argument).
+ if (II->getName().startswith("__builtin_") ||
+ II->getName().startswith("__is_") ||
+ II->getName().startswith("__has_"))
+ return true;
+ return llvm::StringSwitch<bool>(II->getName())
+ .Case("__array_rank", true)
+ .Case("__array_extent", true)
+ .Case("__reference_binds_to_temporary", true)
+ .Case("__underlying_type", true)
+ .Default(false);
} else {
return llvm::StringSwitch<bool>(II->getName())
- .Case("__make_integer_seq", LangOpts.CPlusPlus)
- .Case("__type_pack_element", LangOpts.CPlusPlus)
- .Case("__builtin_available", true)
- .Case("__is_target_arch", true)
- .Case("__is_target_vendor", true)
- .Case("__is_target_os", true)
- .Case("__is_target_environment", true)
- .Case("__builtin_LINE", true)
- .Case("__builtin_FILE", true)
- .Case("__builtin_FUNCTION", true)
- .Case("__builtin_COLUMN", true)
- .Case("__builtin_bit_cast", true)
- .Default(false);
+ // Report builtin templates as being builtins.
+ .Case("__make_integer_seq", LangOpts.CPlusPlus)
+ .Case("__type_pack_element", LangOpts.CPlusPlus)
+ // Likewise for some builtin preprocessor macros.
+ // FIXME: This is inconsistent; we usually suggest detecting
+ // builtin macros via #ifdef. Don't add more cases here.
+ .Case("__is_target_arch", true)
+ .Case("__is_target_vendor", true)
+ .Case("__is_target_os", true)
+ .Case("__is_target_environment", true)
+ .Default(false);
}
});
} else if (II == Ident__is_identifier) {
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 4e4db668551f..79953804b5d3 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -121,6 +121,40 @@ void PragmaNamespace::HandlePragma(Preprocessor &PP,
// Preprocessor Pragma Directive Handling.
//===----------------------------------------------------------------------===//
+namespace {
+// TokenCollector provides the option to collect tokens that were "read"
+// and return them to the stream to be read later.
+// Currently used when reading _Pragma/__pragma directives.
+struct TokenCollector {
+ Preprocessor &Self;
+ bool Collect;
+ SmallVector<Token, 3> Tokens;
+ Token &Tok;
+
+ void lex() {
+ if (Collect)
+ Tokens.push_back(Tok);
+ Self.Lex(Tok);
+ }
+
+ void revert() {
+ assert(Collect && "did not collect tokens");
+ assert(!Tokens.empty() && "collected unexpected number of tokens");
+
+ // Push the ( "string" ) tokens into the token stream.
+ auto Toks = std::make_unique<Token[]>(Tokens.size());
+ std::copy(Tokens.begin() + 1, Tokens.end(), Toks.get());
+ Toks[Tokens.size() - 1] = Tok;
+ Self.EnterTokenStream(std::move(Toks), Tokens.size(),
+ /*DisableMacroExpansion*/ true,
+ /*IsReinject*/ true);
+
+ // ... and return the pragma token unchanged.
+ Tok = *Tokens.begin();
+ }
+};
+} // namespace
+
/// HandlePragmaDirective - The "\#pragma" directive has been parsed. Lex the
/// rest of the pragma, passing it to the registered pragma handlers.
void Preprocessor::HandlePragmaDirective(PragmaIntroducer Introducer) {
@@ -166,35 +200,6 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
// In Case #2, we check the syntax now, but then put the tokens back into the
// token stream for later consumption.
- struct TokenCollector {
- Preprocessor &Self;
- bool Collect;
- SmallVector<Token, 3> Tokens;
- Token &Tok;
-
- void lex() {
- if (Collect)
- Tokens.push_back(Tok);
- Self.Lex(Tok);
- }
-
- void revert() {
- assert(Collect && "did not collect tokens");
- assert(!Tokens.empty() && "collected unexpected number of tokens");
-
- // Push the ( "string" ) tokens into the token stream.
- auto Toks = llvm::make_unique<Token[]>(Tokens.size());
- std::copy(Tokens.begin() + 1, Tokens.end(), Toks.get());
- Toks[Tokens.size() - 1] = Tok;
- Self.EnterTokenStream(std::move(Toks), Tokens.size(),
- /*DisableMacroExpansion*/ true,
- /*IsReinject*/ true);
-
- // ... and return the _Pragma token unchanged.
- Tok = *Tokens.begin();
- }
- };
-
TokenCollector Toks = {*this, InMacroArgPreExpansion, {}, Tok};
// Remember the pragma token location.
@@ -328,11 +333,15 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
/// HandleMicrosoft__pragma - Like Handle_Pragma except the pragma text
/// is not enclosed within a string literal.
void Preprocessor::HandleMicrosoft__pragma(Token &Tok) {
+ // During macro pre-expansion, check the syntax now but put the tokens back
+ // into the token stream for later consumption. Same as Handle_Pragma.
+ TokenCollector Toks = {*this, InMacroArgPreExpansion, {}, Tok};
+
// Remember the pragma token location.
SourceLocation PragmaLoc = Tok.getLocation();
// Read the '('.
- Lex(Tok);
+ Toks.lex();
if (Tok.isNot(tok::l_paren)) {
Diag(PragmaLoc, diag::err__Pragma_malformed);
return;
@@ -341,14 +350,14 @@ void Preprocessor::HandleMicrosoft__pragma(Token &Tok) {
// Get the tokens enclosed within the __pragma(), as well as the final ')'.
SmallVector<Token, 32> PragmaToks;
int NumParens = 0;
- Lex(Tok);
+ Toks.lex();
while (Tok.isNot(tok::eof)) {
PragmaToks.push_back(Tok);
if (Tok.is(tok::l_paren))
NumParens++;
else if (Tok.is(tok::r_paren) && NumParens-- == 0)
break;
- Lex(Tok);
+ Toks.lex();
}
if (Tok.is(tok::eof)) {
@@ -356,6 +365,12 @@ void Preprocessor::HandleMicrosoft__pragma(Token &Tok) {
return;
}
+ // If we're expanding a macro argument, put the tokens back.
+ if (InMacroArgPreExpansion) {
+ Toks.revert();
+ return;
+ }
+
PragmaToks.front().setFlag(Token::LeadingSpace);
// Replace the ')' with an EOD to mark the end of the pragma.
@@ -498,7 +513,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
// Search include directories for this file.
const DirectoryLookup *CurDir;
- const FileEntry *File =
+ Optional<FileEntryRef> File =
LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr,
nullptr, CurDir, nullptr, nullptr, nullptr, nullptr, nullptr);
if (!File) {
@@ -1722,7 +1737,7 @@ struct PragmaARCCFCodeAuditedHandler : public PragmaHandler {
PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
// The start location of the active audit.
- SourceLocation BeginLoc = PP.getPragmaARCCFCodeAuditedLoc();
+ SourceLocation BeginLoc = PP.getPragmaARCCFCodeAuditedInfo().second;
// The start location we want after processing this.
SourceLocation NewLoc;
@@ -1743,7 +1758,7 @@ struct PragmaARCCFCodeAuditedHandler : public PragmaHandler {
NewLoc = SourceLocation();
}
- PP.setPragmaARCCFCodeAuditedLoc(NewLoc);
+ PP.setPragmaARCCFCodeAuditedInfo(NameTok.getIdentifierInfo(), NewLoc);
}
};
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index bdc5fbcd2bea..82007732a9b1 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -158,6 +158,11 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
if (this->PPOpts->GeneratePreamble)
PreambleConditionalStack.startRecording();
+
+ ExcludedConditionalDirectiveSkipMappings =
+ this->PPOpts->ExcludedConditionalDirectiveSkipMappings;
+ if (ExcludedConditionalDirectiveSkipMappings)
+ ExcludedConditionalDirectiveSkipMappings->clear();
}
Preprocessor::~Preprocessor() {
@@ -209,7 +214,7 @@ void Preprocessor::InitializeForModelFile() {
// Reset pragmas
PragmaHandlersBackup = std::move(PragmaHandlers);
- PragmaHandlers = llvm::make_unique<PragmaNamespace>(StringRef());
+ PragmaHandlers = std::make_unique<PragmaNamespace>(StringRef());
RegisterBuiltinPragmas();
// Reset PredefinesFileID
@@ -563,7 +568,7 @@ void Preprocessor::EnterMainSourceFile() {
// Lookup and save the FileID for the through header. If it isn't found
// in the search path, it's a fatal error.
const DirectoryLookup *CurDir;
- const FileEntry *File = LookupFile(
+ Optional<FileEntryRef> File = LookupFile(
SourceLocation(), PPOpts->PCHThroughHeader,
/*isAngled=*/false, /*FromDir=*/nullptr, /*FromFile=*/nullptr, CurDir,
/*SearchPath=*/nullptr, /*RelativePath=*/nullptr,
@@ -575,7 +580,7 @@ void Preprocessor::EnterMainSourceFile() {
return;
}
setPCHThroughHeaderFileID(
- SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User));
+ SourceMgr.createFileID(*File, SourceLocation(), SrcMgr::C_User));
}
// Skip tokens from the Predefines and if needed the main file.
@@ -1129,7 +1134,7 @@ bool Preprocessor::LexAfterModuleImport(Token &Result) {
// Allocate a holding buffer for a sequence of tokens and introduce it into
// the token stream.
auto EnterTokens = [this](ArrayRef<Token> Toks) {
- auto ToksCopy = llvm::make_unique<Token[]>(Toks.size());
+ auto ToksCopy = std::make_unique<Token[]>(Toks.size());
std::copy(Toks.begin(), Toks.end(), ToksCopy.get());
EnterTokenStream(std::move(ToksCopy), Toks.size(),
/*DisableMacroExpansion*/ true, /*IsReinject*/ false);
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index a7957e82e495..da5681aaf478 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -383,18 +383,10 @@ void TokenLexer::ExpandFunctionArguments() {
SourceLocation ExpansionLocEnd =
getExpansionLocForMacroDefLoc(Tokens[I+1].getLocation());
- Token Res;
- if (CurTok.is(tok::hash)) // Stringify
- Res = ActualArgs->getStringifiedArgument(ArgNo, PP,
- ExpansionLocStart,
- ExpansionLocEnd);
- else {
- // 'charify': don't bother caching these.
- Res = MacroArgs::StringifyArgument(ActualArgs->getUnexpArgument(ArgNo),
- PP, true,
- ExpansionLocStart,
- ExpansionLocEnd);
- }
+ bool Charify = CurTok.is(tok::hashat);
+ const Token *UnexpArg = ActualArgs->getUnexpArgument(ArgNo);
+ Token Res = MacroArgs::StringifyArgument(
+ UnexpArg, PP, Charify, ExpansionLocStart, ExpansionLocEnd);
Res.setFlag(Token::StringifiedInMacro);
// The stringified/charified string leading space flag gets set to match
diff --git a/lib/Lex/UnicodeCharSets.h b/lib/Lex/UnicodeCharSets.h
index d56bc8ef6721..74dd57fdf118 100644
--- a/lib/Lex/UnicodeCharSets.h
+++ b/lib/Lex/UnicodeCharSets.h
@@ -215,7 +215,7 @@ static const llvm::sys::UnicodeCharRange C99AllowedIDCharRanges[] = {
// Digits (2)
{ 0x06F0, 0x06F9 },
- // Devanagari and Special characeter 0x093D.
+ // Devanagari and Special character 0x093D.
{ 0x0901, 0x0903 }, { 0x0905, 0x0939 }, { 0x093D, 0x094D },
{ 0x0950, 0x0952 }, { 0x0958, 0x0963 },
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index a1abf8269c45..aa314da8e5b4 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -986,7 +986,7 @@ public:
// Put back the original tokens.
Self.SkipUntil(EndKind, StopAtSemi | StopBeforeMatch);
if (Toks.size()) {
- auto Buffer = llvm::make_unique<Token[]>(Toks.size());
+ auto Buffer = std::make_unique<Token[]>(Toks.size());
std::copy(Toks.begin() + 1, Toks.end(), Buffer.get());
Buffer[Toks.size() - 1] = Self.Tok;
Self.PP.EnterTokenStream(std::move(Buffer), Toks.size(), true,
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 73b4f50fda46..b248d7582d84 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -86,8 +86,8 @@ static bool isAttributeLateParsed(const IdentifierInfo &II) {
}
/// Check if the a start and end source location expand to the same macro.
-bool FindLocsWithCommonFileID(Preprocessor &PP, SourceLocation StartLoc,
- SourceLocation EndLoc) {
+static bool FindLocsWithCommonFileID(Preprocessor &PP, SourceLocation StartLoc,
+ SourceLocation EndLoc) {
if (!StartLoc.isMacroID() || !EndLoc.isMacroID())
return false;
@@ -335,6 +335,7 @@ unsigned Parser::ParseAttributeArgsCommon(
ConsumeParen();
bool ChangeKWThisToIdent = attributeTreatsKeywordThisAsIdentifier(*AttrName);
+ bool AttributeIsTypeArgAttr = attributeIsTypeArgAttr(*AttrName);
// Interpret "kw_this" as an identifier if the attributed requests it.
if (ChangeKWThisToIdent && Tok.is(tok::kw_this))
@@ -346,7 +347,7 @@ unsigned Parser::ParseAttributeArgsCommon(
bool IsIdentifierArg = attributeHasIdentifierArg(*AttrName) ||
attributeHasVariadicIdentifierArg(*AttrName);
ParsedAttr::Kind AttrKind =
- ParsedAttr::getKind(AttrName, ScopeName, Syntax);
+ ParsedAttr::getParsedKind(AttrName, ScopeName, Syntax);
// If we don't know how to parse this attribute, but this is the only
// token in this argument, assume it's meant to be an identifier.
@@ -360,6 +361,7 @@ unsigned Parser::ParseAttributeArgsCommon(
ArgExprs.push_back(ParseIdentifierLoc());
}
+ ParsedType TheParsedType;
if (!ArgExprs.empty() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren)) {
// Eat the comma.
if (!ArgExprs.empty())
@@ -372,8 +374,17 @@ unsigned Parser::ParseAttributeArgsCommon(
Tok.setKind(tok::identifier);
ExprResult ArgExpr;
- if (Tok.is(tok::identifier) &&
- attributeHasVariadicIdentifierArg(*AttrName)) {
+ if (AttributeIsTypeArgAttr) {
+ TypeResult T = ParseTypeName();
+ if (T.isInvalid()) {
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return 0;
+ }
+ if (T.isUsable())
+ TheParsedType = T.get();
+ break; // FIXME: Multiple type arguments are not implemented.
+ } else if (Tok.is(tok::identifier) &&
+ attributeHasVariadicIdentifierArg(*AttrName)) {
ArgExprs.push_back(ParseIdentifierLoc());
} else {
bool Uneval = attributeParsedArgsUnevaluated(*AttrName);
@@ -397,14 +408,20 @@ unsigned Parser::ParseAttributeArgsCommon(
SourceLocation RParen = Tok.getLocation();
if (!ExpectAndConsume(tok::r_paren)) {
SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc;
- Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc,
- ArgExprs.data(), ArgExprs.size(), Syntax);
+
+ if (AttributeIsTypeArgAttr && !TheParsedType.get().isNull()) {
+ Attrs.addNewTypeAttr(AttrName, SourceRange(AttrNameLoc, RParen),
+ ScopeName, ScopeLoc, TheParsedType, Syntax);
+ } else {
+ Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc,
+ ArgExprs.data(), ArgExprs.size(), Syntax);
+ }
}
if (EndLoc)
*EndLoc = RParen;
- return static_cast<unsigned>(ArgExprs.size());
+ return static_cast<unsigned>(ArgExprs.size() + !TheParsedType.get().isNull());
}
/// Parse the arguments to a parameterized GNU attribute or
@@ -421,7 +438,7 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
ParsedAttr::Kind AttrKind =
- ParsedAttr::getKind(AttrName, ScopeName, Syntax);
+ ParsedAttr::getParsedKind(AttrName, ScopeName, Syntax);
if (AttrKind == ParsedAttr::AT_Availability) {
ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
@@ -471,7 +488,7 @@ unsigned Parser::ParseClangAttributeArgs(
assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
ParsedAttr::Kind AttrKind =
- ParsedAttr::getKind(AttrName, ScopeName, Syntax);
+ ParsedAttr::getParsedKind(AttrName, ScopeName, Syntax);
switch (AttrKind) {
default:
@@ -1672,9 +1689,9 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs,
if (!AL.isCXX11Attribute() && !AL.isC2xAttribute())
continue;
if (AL.getKind() == ParsedAttr::UnknownAttribute)
- Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL.getName();
+ Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL;
else {
- Diag(AL.getLoc(), DiagID) << AL.getName();
+ Diag(AL.getLoc(), DiagID) << AL;
AL.setInvalid();
}
}
@@ -1724,9 +1741,10 @@ void Parser::stripTypeAttributesOffDeclSpec(ParsedAttributesWithRange &Attrs,
/// [C++11/C11] static_assert-declaration
/// others... [FIXME]
///
-Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
- SourceLocation &DeclEnd,
- ParsedAttributesWithRange &attrs) {
+Parser::DeclGroupPtrTy
+Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd,
+ ParsedAttributesWithRange &attrs,
+ SourceLocation *DeclSpecStart) {
ParenBraceBracketBalancer BalancerRAIIObj(*this);
// Must temporarily exit the objective-c container scope for
// parsing c none objective-c decls.
@@ -1746,8 +1764,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
SourceLocation InlineLoc = ConsumeToken();
return ParseNamespace(Context, DeclEnd, InlineLoc);
}
- return ParseSimpleDeclaration(Context, DeclEnd, attrs,
- true);
+ return ParseSimpleDeclaration(Context, DeclEnd, attrs, true, nullptr,
+ DeclSpecStart);
case tok::kw_namespace:
ProhibitAttributes(attrs);
return ParseNamespace(Context, DeclEnd);
@@ -1760,7 +1778,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
SingleDecl = ParseStaticAssertDeclaration(DeclEnd);
break;
default:
- return ParseSimpleDeclaration(Context, DeclEnd, attrs, true);
+ return ParseSimpleDeclaration(Context, DeclEnd, attrs, true, nullptr,
+ DeclSpecStart);
}
// This routine returns a DeclGroup, if the thing we parsed only contains a
@@ -1785,11 +1804,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context,
/// If FRI is non-null, we might be parsing a for-range-declaration instead
/// of a simple-declaration. If we find that we are, we also parse the
/// for-range-initializer, and place it here.
-Parser::DeclGroupPtrTy
-Parser::ParseSimpleDeclaration(DeclaratorContext Context,
- SourceLocation &DeclEnd,
- ParsedAttributesWithRange &Attrs,
- bool RequireSemi, ForRangeInit *FRI) {
+///
+/// DeclSpecStart is used when decl-specifiers are parsed before parsing
+/// the Declaration. The SourceLocation for this Decl is set to
+/// DeclSpecStart if DeclSpecStart is non-null.
+Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(
+ DeclaratorContext Context, SourceLocation &DeclEnd,
+ ParsedAttributesWithRange &Attrs, bool RequireSemi, ForRangeInit *FRI,
+ SourceLocation *DeclSpecStart) {
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this);
@@ -1819,6 +1841,9 @@ Parser::ParseSimpleDeclaration(DeclaratorContext Context,
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
+ if (DeclSpecStart)
+ DS.SetRangeStart(*DeclSpecStart);
+
DS.takeAttributesFrom(Attrs);
return ParseDeclGroup(DS, Context, &DeclEnd, FRI);
}
@@ -2075,6 +2100,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
bool IsForRangeLoop = false;
if (TryConsumeToken(tok::colon, FRI->ColonLoc)) {
IsForRangeLoop = true;
+ if (getLangOpts().OpenMP)
+ Actions.startOpenMPCXXRangeFor();
if (Tok.is(tok::l_brace))
FRI->RangeExpr = ParseBraceInitializer();
else
@@ -2489,7 +2516,7 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
// Issue diagnostic and remove constexpr specifier if present.
if (DS.hasConstexprSpecifier() && DSC != DeclSpecContext::DSC_condition) {
Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr)
- << (DS.getConstexprSpecifier() == CSK_consteval);
+ << DS.getConstexprSpecifier();
DS.ClearConstexprSpec();
}
}
@@ -2902,28 +2929,29 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
IdentifierInfo *Name = AfterScope.getIdentifierInfo();
Sema::NameClassification Classification = Actions.ClassifyName(
getCurScope(), SS, Name, AfterScope.getLocation(), Next,
- /*IsAddressOfOperand=*/false, /*CCC=*/nullptr);
+ /*CCC=*/nullptr);
switch (Classification.getKind()) {
case Sema::NC_Error:
SkipMalformedDecl();
return true;
case Sema::NC_Keyword:
- case Sema::NC_NestedNameSpecifier:
- llvm_unreachable("typo correction and nested name specifiers not "
- "possible here");
+ llvm_unreachable("typo correction is not possible here");
case Sema::NC_Type:
case Sema::NC_TypeTemplate:
+ case Sema::NC_UndeclaredNonType:
+ case Sema::NC_UndeclaredTemplate:
// Not a previously-declared non-type entity.
MightBeDeclarator = false;
break;
case Sema::NC_Unknown:
- case Sema::NC_Expression:
+ case Sema::NC_NonType:
+ case Sema::NC_DependentNonType:
+ case Sema::NC_ContextIndependentExpr:
case Sema::NC_VarTemplate:
case Sema::NC_FunctionTemplate:
- case Sema::NC_UndeclaredTemplate:
// Might be a redeclaration of a prior entity.
break;
}
@@ -3549,6 +3577,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isStorageClass = true;
break;
case tok::kw__Thread_local:
+ if (!getLangOpts().C11)
+ Diag(Tok, diag::ext_c11_feature) << Tok.getName();
isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS__Thread_local,
Loc, PrevSpec, DiagID);
isStorageClass = true;
@@ -3599,14 +3629,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
}
case tok::kw__Noreturn:
if (!getLangOpts().C11)
- Diag(Loc, diag::ext_c11_noreturn);
+ Diag(Tok, diag::ext_c11_feature) << Tok.getName();
isInvalid = DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID);
break;
// alignment-specifier
case tok::kw__Alignas:
if (!getLangOpts().C11)
- Diag(Tok, diag::ext_c11_alignment) << Tok.getName();
+ Diag(Tok, diag::ext_c11_feature) << Tok.getName();
ParseAlignmentSpecifier(DS.getAttributes());
continue;
@@ -3626,15 +3656,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.setModulePrivateSpec(Loc, PrevSpec, DiagID);
break;
- // constexpr
+ // constexpr, consteval, constinit specifiers
case tok::kw_constexpr:
isInvalid = DS.SetConstexprSpec(CSK_constexpr, Loc, PrevSpec, DiagID);
break;
-
- // consteval
case tok::kw_consteval:
isInvalid = DS.SetConstexprSpec(CSK_consteval, Loc, PrevSpec, DiagID);
break;
+ case tok::kw_constinit:
+ isInvalid = DS.SetConstexprSpec(CSK_constinit, Loc, PrevSpec, DiagID);
+ break;
// type-specifier
case tok::kw_short:
@@ -3662,10 +3693,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
DiagID);
break;
case tok::kw__Complex:
+ if (!getLangOpts().C99)
+ Diag(Tok, diag::ext_c99_feature) << Tok.getName();
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_complex, Loc, PrevSpec,
DiagID);
break;
case tok::kw__Imaginary:
+ if (!getLangOpts().C99)
+ Diag(Tok, diag::ext_c99_feature) << Tok.getName();
isInvalid = DS.SetTypeSpecComplex(DeclSpec::TSC_imaginary, Loc, PrevSpec,
DiagID);
break;
@@ -3746,6 +3781,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
break;
case tok::kw_bool:
case tok::kw__Bool:
+ if (Tok.is(tok::kw__Bool) && !getLangOpts().C99)
+ Diag(Tok, diag::ext_c99_feature) << Tok.getName();
+
if (Tok.is(tok::kw_bool) &&
DS.getTypeSpecType() != DeclSpec::TST_unspecified &&
DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
@@ -3889,6 +3927,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// If the _Atomic keyword is immediately followed by a left parenthesis,
// it is interpreted as a type specifier (with a type name), not as a
// type qualifier.
+ if (!getLangOpts().C11)
+ Diag(Tok, diag::ext_c11_feature) << Tok.getName();
+
if (NextToken().is(tok::l_paren)) {
ParseAtomicSpecifier(DS);
continue;
@@ -4081,7 +4122,7 @@ void Parser::ParseStructDeclaration(
/// [OBC] '@' 'defs' '(' class-name ')'
///
void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
- unsigned TagType, Decl *TagDecl) {
+ DeclSpec::TST TagType, Decl *TagDecl) {
PrettyDeclStackTraceEntry CrashInfo(Actions.Context, TagDecl, RecordLoc,
"parsing struct/union body");
assert(!getLangOpts().CPlusPlus && "C++ declarations not supported");
@@ -4131,6 +4172,14 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
continue;
}
+ if (tok::isPragmaAnnotation(Tok.getKind())) {
+ Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl)
+ << DeclSpec::getSpecifierName(
+ TagType, Actions.getASTContext().getPrintingPolicy());
+ ConsumeAnnotationToken();
+ continue;
+ }
+
if (!Tok.is(tok::at)) {
auto CFieldCallback = [&](ParsingFieldDeclarator &FD) {
// Install the declarator into the current TagDecl.
@@ -4632,8 +4681,10 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
ExprResult AssignedVal;
EnumAvailabilityDiags.emplace_back(*this);
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
if (TryConsumeToken(tok::equal, EqualLoc)) {
- AssignedVal = ParseConstantExpression();
+ AssignedVal = ParseConstantExpressionInExprEvalContext();
if (AssignedVal.isInvalid())
SkipUntil(tok::comma, tok::r_brace, StopBeforeMatch);
}
@@ -5038,8 +5089,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::annot_decltype:
case tok::kw_constexpr:
- // C++20 consteval.
+ // C++20 consteval and constinit.
case tok::kw_consteval:
+ case tok::kw_constinit:
// C11 _Atomic
case tok::kw__Atomic:
@@ -5286,6 +5338,8 @@ void Parser::ParseTypeQualifierListOpt(
case tok::kw__Atomic:
if (!AtomicAllowed)
goto DoneWithTypeQuals;
+ if (!getLangOpts().C11)
+ Diag(Tok, diag::ext_c11_feature) << Tok.getName();
isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID,
getLangOpts());
break;
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 9c61c4da447a..b98ce3e66292 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -862,7 +862,7 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
"Not a static_assert declaration");
if (Tok.is(tok::kw__Static_assert) && !getLangOpts().C11)
- Diag(Tok, diag::ext_c11_static_assert);
+ Diag(Tok, diag::ext_c11_feature) << Tok.getName();
if (Tok.is(tok::kw_static_assert))
Diag(Tok, diag::warn_cxx98_compat_static_assert);
@@ -1313,6 +1313,8 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
case tok::kw_mutable: // struct foo {...} mutable x;
case tok::kw_thread_local: // struct foo {...} thread_local x;
case tok::kw_constexpr: // struct foo {...} constexpr x;
+ case tok::kw_consteval: // struct foo {...} consteval x;
+ case tok::kw_constinit: // struct foo {...} constinit x;
// As shown above, type qualifiers and storage class specifiers absolutely
// can occur after class specifiers according to the grammar. However,
// almost no one actually writes code like this. If we see one of these,
@@ -3134,6 +3136,13 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
TagDecl);
default:
+ if (tok::isPragmaAnnotation(Tok.getKind())) {
+ Diag(Tok.getLocation(), diag::err_pragma_misplaced_in_decl)
+ << DeclSpec::getSpecifierName(TagType,
+ Actions.getASTContext().getPrintingPolicy());
+ ConsumeAnnotationToken();
+ return nullptr;
+ }
return ParseCXXClassMemberDeclaration(AS, AccessAttrs);
}
}
@@ -3907,7 +3916,8 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {
static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
IdentifierInfo *ScopeName) {
- switch (ParsedAttr::getKind(AttrName, ScopeName, ParsedAttr::AS_CXX11)) {
+ switch (
+ ParsedAttr::getParsedKind(AttrName, ScopeName, ParsedAttr::AS_CXX11)) {
case ParsedAttr::AT_CarriesDependency:
case ParsedAttr::AT_Deprecated:
case ParsedAttr::AT_FallThrough:
@@ -4337,7 +4347,7 @@ void Parser::ParseMicrosoftIfExistsClassDeclaration(
while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
// __if_exists, __if_not_exists can nest.
if (Tok.isOneOf(tok::kw___if_exists, tok::kw___if_not_exists)) {
- ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType,
+ ParseMicrosoftIfExistsClassDeclaration(TagType,
AccessAttrs, CurAS);
continue;
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 7a0c07bd3b04..b74a95a3cd4b 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -228,18 +228,16 @@ ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) {
/// Parse a constraint-expression.
///
/// \verbatim
-/// constraint-expression: [Concepts TS temp.constr.decl p1]
+/// constraint-expression: C++2a[temp.constr.decl]p1
/// logical-or-expression
/// \endverbatim
ExprResult Parser::ParseConstraintExpression() {
- // FIXME: this may erroneously consume a function-body as the braced
- // initializer list of a compound literal
- //
- // FIXME: this may erroneously consume a parenthesized rvalue reference
- // declarator as a parenthesized address-of-label expression
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult LHS(ParseCastExpression(/*isUnaryExpression=*/false));
ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr));
-
+ if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get()))
+ return ExprError();
return Res;
}
@@ -573,7 +571,7 @@ class CastExpressionIdValidator final : public CorrectionCandidateCallback {
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<CastExpressionIdValidator>(*this);
+ return std::make_unique<CastExpressionIdValidator>(*this);
}
private:
@@ -840,13 +838,23 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
case tok::annot_primary_expr:
- assert(Res.get() == nullptr && "Stray primary-expression annotation?");
Res = getExprAnnotation(Tok);
ConsumeAnnotationToken();
if (!Res.isInvalid() && Tok.is(tok::less))
checkPotentialAngleBracket(Res);
break;
+ case tok::annot_non_type:
+ case tok::annot_non_type_dependent:
+ case tok::annot_non_type_undeclared: {
+ CXXScopeSpec SS;
+ Token Replacement;
+ Res = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement);
+ assert(!Res.isUnset() &&
+ "should not perform typo correction on annotation token");
+ break;
+ }
+
case tok::kw___super:
case tok::kw_decltype:
// Annotate the token and tail recurse.
@@ -1191,7 +1199,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
}
case tok::kw__Alignof: // unary-expression: '_Alignof' '(' type-name ')'
if (!getLangOpts().C11)
- Diag(Tok, diag::ext_c11_alignment) << Tok.getName();
+ Diag(Tok, diag::ext_c11_feature) << Tok.getName();
LLVM_FALLTHROUGH;
case tok::kw_alignof: // unary-expression: 'alignof' '(' type-id ')'
case tok::kw___alignof: // unary-expression: '__alignof' unary-expression
@@ -1772,12 +1780,12 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
OpKind == tok::arrow ? tok::period : tok::arrow;
ExprResult CorrectedLHS(/*Invalid=*/true);
if (getLangOpts().CPlusPlus && OrigLHS) {
- const bool DiagsAreSuppressed = Diags.getSuppressAllDiagnostics();
- Diags.setSuppressAllDiagnostics(true);
+ // FIXME: Creating a TentativeAnalysisScope from outside Sema is a
+ // hack.
+ Sema::TentativeAnalysisScope Trap(Actions);
CorrectedLHS = Actions.ActOnStartCXXMemberReference(
getCurScope(), OrigLHS, OpLoc, CorrectedOpKind, ObjectType,
MayBePseudoDestructor);
- Diags.setSuppressAllDiagnostics(DiagsAreSuppressed);
}
Expr *Base = LHS.get();
@@ -2733,11 +2741,10 @@ ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) {
/// \endverbatim
ExprResult Parser::ParseGenericSelectionExpression() {
assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected");
- SourceLocation KeyLoc = ConsumeToken();
-
if (!getLangOpts().C11)
- Diag(KeyLoc, diag::ext_c11_generic_selection);
+ Diag(Tok, diag::ext_c11_feature) << Tok.getName();
+ SourceLocation KeyLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume())
return ExprError();
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 85c7e6c6bcdf..a064e4b17587 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -555,27 +555,66 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
return false;
}
-ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOperand,
+ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS,
+ bool isAddressOfOperand,
Token &Replacement) {
- SourceLocation TemplateKWLoc;
- UnqualifiedId Name;
- if (ParseUnqualifiedId(SS,
- /*EnteringContext=*/false,
- /*AllowDestructorName=*/false,
- /*AllowConstructorName=*/false,
- /*AllowDeductionGuide=*/false,
- /*ObjectType=*/nullptr, &TemplateKWLoc, Name))
- return ExprError();
+ ExprResult E;
+
+ // We may have already annotated this id-expression.
+ switch (Tok.getKind()) {
+ case tok::annot_non_type: {
+ NamedDecl *ND = getNonTypeAnnotation(Tok);
+ SourceLocation Loc = ConsumeAnnotationToken();
+ E = Actions.ActOnNameClassifiedAsNonType(getCurScope(), SS, ND, Loc, Tok);
+ break;
+ }
+
+ case tok::annot_non_type_dependent: {
+ IdentifierInfo *II = getIdentifierAnnotation(Tok);
+ SourceLocation Loc = ConsumeAnnotationToken();
+
+ // This is only the direct operand of an & operator if it is not
+ // followed by a postfix-expression suffix.
+ if (isAddressOfOperand && isPostfixExpressionSuffixStart())
+ isAddressOfOperand = false;
+
+ E = Actions.ActOnNameClassifiedAsDependentNonType(SS, II, Loc,
+ isAddressOfOperand);
+ break;
+ }
- // This is only the direct operand of an & operator if it is not
- // followed by a postfix-expression suffix.
- if (isAddressOfOperand && isPostfixExpressionSuffixStart())
- isAddressOfOperand = false;
+ case tok::annot_non_type_undeclared: {
+ assert(SS.isEmpty() &&
+ "undeclared non-type annotation should be unqualified");
+ IdentifierInfo *II = getIdentifierAnnotation(Tok);
+ SourceLocation Loc = ConsumeAnnotationToken();
+ E = Actions.ActOnNameClassifiedAsUndeclaredNonType(II, Loc);
+ break;
+ }
+
+ default:
+ SourceLocation TemplateKWLoc;
+ UnqualifiedId Name;
+ if (ParseUnqualifiedId(SS,
+ /*EnteringContext=*/false,
+ /*AllowDestructorName=*/false,
+ /*AllowConstructorName=*/false,
+ /*AllowDeductionGuide=*/false,
+ /*ObjectType=*/nullptr, &TemplateKWLoc, Name))
+ return ExprError();
+
+ // This is only the direct operand of an & operator if it is not
+ // followed by a postfix-expression suffix.
+ if (isAddressOfOperand && isPostfixExpressionSuffixStart())
+ isAddressOfOperand = false;
+
+ E = Actions.ActOnIdExpression(
+ getCurScope(), SS, TemplateKWLoc, Name, Tok.is(tok::l_paren),
+ isAddressOfOperand, /*CCC=*/nullptr, /*IsInlineAsmIdentifier=*/false,
+ &Replacement);
+ break;
+ }
- ExprResult E = Actions.ActOnIdExpression(
- getCurScope(), SS, TemplateKWLoc, Name, Tok.is(tok::l_paren),
- isAddressOfOperand, /*CCC=*/nullptr, /*IsInlineAsmIdentifier=*/false,
- &Replacement);
if (!E.isInvalid() && !E.isUnset() && Tok.is(tok::less))
checkPotentialAngleBracket(E);
return E;
@@ -1214,7 +1253,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
A.getKind() == ParsedAttr::AT_CUDAHost ||
A.getKind() == ParsedAttr::AT_CUDAGlobal)
Diag(A.getLoc(), diag::warn_cuda_attr_lambda_position)
- << A.getName()->getName();
+ << A.getAttrName()->getName();
};
// FIXME: Consider allowing this as an extension for GCC compatibiblity.
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 7a455484b902..5ab055130dc2 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -39,12 +39,14 @@ bool Parser::MayBeDesignationStart() {
// cases here, and fall back to tentative parsing if those fail.
switch (PP.LookAhead(0).getKind()) {
case tok::equal:
+ case tok::ellipsis:
case tok::r_square:
// Definitely starts a lambda expression.
return false;
case tok::amp:
case tok::kw_this:
+ case tok::star:
case tok::identifier:
// We have to do additional analysis, because these could be the
// start of a constant expression or a lambda capture list.
@@ -114,6 +116,8 @@ static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
/// checking to see if the token stream starts with a designator.
///
+/// C99:
+///
/// designation:
/// designator-list '='
/// [GNU] array-designator
@@ -131,6 +135,21 @@ static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
/// '[' constant-expression ']'
/// [GNU] '[' constant-expression '...' constant-expression ']'
///
+/// C++20:
+///
+/// designated-initializer-list:
+/// designated-initializer-clause
+/// designated-initializer-list ',' designated-initializer-clause
+///
+/// designated-initializer-clause:
+/// designator brace-or-equal-initializer
+///
+/// designator:
+/// '.' identifier
+///
+/// We allow the C99 syntax extensions in C++20, but do not allow the C++20
+/// extension (a braced-init-list after the designator with no '=') in C99.
+///
/// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an
/// initializer (because it is an expression). We need to consider this case
/// when parsing array designators.
@@ -363,6 +382,14 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
ParseInitializer());
}
+ // Handle a C++20 braced designated initialization, which results in
+ // direct-list-initialization of the aggregate element. We allow this as an
+ // extension from C++11 onwards (when direct-list-initialization was added).
+ if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus11) {
+ return Actions.ActOnDesignatedInitializer(Desig, SourceLocation(), false,
+ ParseBraceInitializer());
+ }
+
// We read some number of designators and found something that isn't an = or
// an initializer. If we have exactly one array designator, this
// is the GNU 'designation: array-designator' extension. Otherwise, it is a
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 8937a0986c95..42d6221a7333 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -710,7 +710,6 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
case tok::objc_required:
case tok::objc_optional:
// This is only valid on protocols.
- // FIXME: Should this check for ObjC2 being enabled?
if (contextKey != tok::objc_protocol)
Diag(AtLoc, diag::err_objc_directive_only_in_protocol);
else
@@ -718,9 +717,6 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
break;
case tok::objc_property:
- if (!getLangOpts().ObjC)
- Diag(AtLoc, diag::err_objc_properties_require_objc2);
-
ObjCDeclSpec OCDS;
SourceLocation LParenLoc;
// Parse property attribute list, if any.
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index 52a68f6d6935..91fe10e667db 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -17,6 +17,7 @@
#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/UniqueVector.h"
using namespace clang;
@@ -42,6 +43,8 @@ enum OpenMPDirectiveKindEx {
OMPD_teams_distribute_parallel,
OMPD_target_teams_distribute_parallel,
OMPD_mapper,
+ OMPD_variant,
+ OMPD_parallel_master,
};
class DeclDirectiveListParserHelper final {
@@ -80,6 +83,7 @@ static unsigned getOpenMPDirectiveKindEx(StringRef S) {
.Case("reduction", OMPD_reduction)
.Case("update", OMPD_update)
.Case("mapper", OMPD_mapper)
+ .Case("variant", OMPD_variant)
.Default(OMPD_unknown);
}
@@ -93,6 +97,7 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) {
{OMPD_declare, OMPD_mapper, OMPD_declare_mapper},
{OMPD_declare, OMPD_simd, OMPD_declare_simd},
{OMPD_declare, OMPD_target, OMPD_declare_target},
+ {OMPD_declare, OMPD_variant, OMPD_declare_variant},
{OMPD_distribute, OMPD_parallel, OMPD_distribute_parallel},
{OMPD_distribute_parallel, OMPD_for, OMPD_distribute_parallel_for},
{OMPD_distribute_parallel_for, OMPD_simd,
@@ -131,7 +136,11 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) {
{OMPD_target_teams_distribute_parallel, OMPD_for,
OMPD_target_teams_distribute_parallel_for},
{OMPD_target_teams_distribute_parallel_for, OMPD_simd,
- OMPD_target_teams_distribute_parallel_for_simd}};
+ OMPD_target_teams_distribute_parallel_for_simd},
+ {OMPD_master, OMPD_taskloop, OMPD_master_taskloop},
+ {OMPD_master_taskloop, OMPD_simd, OMPD_master_taskloop_simd},
+ {OMPD_parallel, OMPD_master, OMPD_parallel_master},
+ {OMPD_parallel_master, OMPD_taskloop, OMPD_parallel_master_taskloop}};
enum { CancellationPoint = 0, DeclareReduction = 1, TargetData = 2 };
Token Tok = P.getCurToken();
unsigned DKind =
@@ -752,6 +761,7 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,
/*IsReinject*/ true);
// Consume the previously pushed token.
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
FNContextRAII FnContext(*this, Ptr);
OMPDeclareSimdDeclAttr::BranchStateTy BS =
@@ -782,25 +792,386 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,
LinModifiers, Steps, SourceRange(Loc, EndLoc));
}
+/// Parse optional 'score' '(' <expr> ')' ':'.
+static ExprResult parseContextScore(Parser &P) {
+ ExprResult ScoreExpr;
+ SmallString<16> Buffer;
+ StringRef SelectorName =
+ P.getPreprocessor().getSpelling(P.getCurToken(), Buffer);
+ OMPDeclareVariantAttr::ScoreType ScoreKind =
+ OMPDeclareVariantAttr::ScoreUnknown;
+ (void)OMPDeclareVariantAttr::ConvertStrToScoreType(SelectorName, ScoreKind);
+ if (ScoreKind == OMPDeclareVariantAttr::ScoreUnknown)
+ return ScoreExpr;
+ assert(ScoreKind == OMPDeclareVariantAttr::ScoreSpecified &&
+ "Expected \"score\" clause.");
+ (void)P.ConsumeToken();
+ SourceLocation RLoc;
+ ScoreExpr = P.ParseOpenMPParensExpr(SelectorName, RLoc);
+ // Parse ':'
+ if (P.getCurToken().is(tok::colon))
+ (void)P.ConsumeAnyToken();
+ else
+ P.Diag(P.getCurToken(), diag::warn_pragma_expected_colon)
+ << "context selector score clause";
+ return ScoreExpr;
+}
+
+/// Parse context selector for 'implementation' selector set:
+/// 'vendor' '(' [ 'score' '(' <score _expr> ')' ':' ] <vendor> { ',' <vendor> }
+/// ')'
+static void parseImplementationSelector(
+ Parser &P, SourceLocation Loc, llvm::StringMap<SourceLocation> &UsedCtx,
+ llvm::function_ref<void(SourceRange,
+ const Sema::OpenMPDeclareVariantCtsSelectorData &)>
+ Callback) {
+ const Token &Tok = P.getCurToken();
+ // Parse inner context selector set name, if any.
+ if (!Tok.is(tok::identifier)) {
+ P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected)
+ << "implementation";
+ // Skip until either '}', ')', or end of directive.
+ while (!P.SkipUntil(tok::r_brace, tok::r_paren,
+ tok::annot_pragma_openmp_end, Parser::StopBeforeMatch))
+ ;
+ return;
+ }
+ SmallString<16> Buffer;
+ StringRef CtxSelectorName = P.getPreprocessor().getSpelling(Tok, Buffer);
+ auto Res = UsedCtx.try_emplace(CtxSelectorName, Tok.getLocation());
+ if (!Res.second) {
+ // OpenMP 5.0, 2.3.2 Context Selectors, Restrictions.
+ // Each trait-selector-name can only be specified once.
+ P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_ctx_mutiple_use)
+ << CtxSelectorName << "implementation";
+ P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here)
+ << CtxSelectorName;
+ }
+ OMPDeclareVariantAttr::CtxSelectorType CSKind =
+ OMPDeclareVariantAttr::CtxUnknown;
+ (void)OMPDeclareVariantAttr::ConvertStrToCtxSelectorType(CtxSelectorName,
+ CSKind);
+ (void)P.ConsumeToken();
+ switch (CSKind) {
+ case OMPDeclareVariantAttr::CtxVendor: {
+ // Parse '('.
+ BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end);
+ (void)T.expectAndConsume(diag::err_expected_lparen_after,
+ CtxSelectorName.data());
+ const ExprResult Score = parseContextScore(P);
+ llvm::UniqueVector<llvm::SmallString<16>> Vendors;
+ do {
+ // Parse <vendor>.
+ StringRef VendorName;
+ if (Tok.is(tok::identifier)) {
+ Buffer.clear();
+ VendorName = P.getPreprocessor().getSpelling(P.getCurToken(), Buffer);
+ (void)P.ConsumeToken();
+ if (!VendorName.empty())
+ Vendors.insert(VendorName);
+ } else {
+ P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_item_expected)
+ << "vendor identifier"
+ << "vendor"
+ << "implementation";
+ }
+ if (!P.TryConsumeToken(tok::comma) && Tok.isNot(tok::r_paren)) {
+ P.Diag(Tok, diag::err_expected_punc)
+ << (VendorName.empty() ? "vendor name" : VendorName);
+ }
+ } while (Tok.is(tok::identifier));
+ // Parse ')'.
+ (void)T.consumeClose();
+ if (!Vendors.empty()) {
+ SmallVector<StringRef, 4> ImplVendors(Vendors.size());
+ llvm::copy(Vendors, ImplVendors.begin());
+ Sema::OpenMPDeclareVariantCtsSelectorData Data(
+ OMPDeclareVariantAttr::CtxSetImplementation, CSKind,
+ llvm::makeMutableArrayRef(ImplVendors.begin(), ImplVendors.size()),
+ Score);
+ Callback(SourceRange(Loc, Tok.getLocation()), Data);
+ }
+ break;
+ }
+ case OMPDeclareVariantAttr::CtxUnknown:
+ P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected)
+ << "implementation";
+ // Skip until either '}', ')', or end of directive.
+ while (!P.SkipUntil(tok::r_brace, tok::r_paren,
+ tok::annot_pragma_openmp_end, Parser::StopBeforeMatch))
+ ;
+ return;
+ }
+}
+
+/// Parses clauses for 'declare variant' directive.
+/// clause:
+/// <selector_set_name> '=' '{' <context_selectors> '}'
+/// [ ',' <selector_set_name> '=' '{' <context_selectors> '}' ]
+bool Parser::parseOpenMPContextSelectors(
+ SourceLocation Loc,
+ llvm::function_ref<void(SourceRange,
+ const Sema::OpenMPDeclareVariantCtsSelectorData &)>
+ Callback) {
+ llvm::StringMap<SourceLocation> UsedCtxSets;
+ do {
+ // Parse inner context selector set name.
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_omp_declare_variant_no_ctx_selector)
+ << getOpenMPClauseName(OMPC_match);
+ return true;
+ }
+ SmallString<16> Buffer;
+ StringRef CtxSelectorSetName = PP.getSpelling(Tok, Buffer);
+ auto Res = UsedCtxSets.try_emplace(CtxSelectorSetName, Tok.getLocation());
+ if (!Res.second) {
+ // OpenMP 5.0, 2.3.2 Context Selectors, Restrictions.
+ // Each trait-set-selector-name can only be specified once.
+ Diag(Tok.getLocation(), diag::err_omp_declare_variant_ctx_set_mutiple_use)
+ << CtxSelectorSetName;
+ Diag(Res.first->getValue(),
+ diag::note_omp_declare_variant_ctx_set_used_here)
+ << CtxSelectorSetName;
+ }
+ // Parse '='.
+ (void)ConsumeToken();
+ if (Tok.isNot(tok::equal)) {
+ Diag(Tok.getLocation(), diag::err_omp_declare_variant_equal_expected)
+ << CtxSelectorSetName;
+ return true;
+ }
+ (void)ConsumeToken();
+ // TBD: add parsing of known context selectors.
+ // Unknown selector - just ignore it completely.
+ {
+ // Parse '{'.
+ BalancedDelimiterTracker TBr(*this, tok::l_brace,
+ tok::annot_pragma_openmp_end);
+ if (TBr.expectAndConsume(diag::err_expected_lbrace_after, "="))
+ return true;
+ OMPDeclareVariantAttr::CtxSelectorSetType CSSKind =
+ OMPDeclareVariantAttr::CtxSetUnknown;
+ (void)OMPDeclareVariantAttr::ConvertStrToCtxSelectorSetType(
+ CtxSelectorSetName, CSSKind);
+ llvm::StringMap<SourceLocation> UsedCtx;
+ do {
+ switch (CSSKind) {
+ case OMPDeclareVariantAttr::CtxSetImplementation:
+ parseImplementationSelector(*this, Loc, UsedCtx, Callback);
+ break;
+ case OMPDeclareVariantAttr::CtxSetUnknown:
+ // Skip until either '}', ')', or end of directive.
+ while (!SkipUntil(tok::r_brace, tok::r_paren,
+ tok::annot_pragma_openmp_end, StopBeforeMatch))
+ ;
+ break;
+ }
+ const Token PrevTok = Tok;
+ if (!TryConsumeToken(tok::comma) && Tok.isNot(tok::r_brace))
+ Diag(Tok, diag::err_omp_expected_comma_brace)
+ << (PrevTok.isAnnotation() ? "context selector trait"
+ : PP.getSpelling(PrevTok));
+ } while (Tok.is(tok::identifier));
+ // Parse '}'.
+ (void)TBr.consumeClose();
+ }
+ // Consume ','
+ if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end))
+ (void)ExpectAndConsume(tok::comma);
+ } while (Tok.isAnyIdentifier());
+ return false;
+}
+
+/// Parse clauses for '#pragma omp declare variant ( variant-func-id ) clause'.
+void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr,
+ CachedTokens &Toks,
+ SourceLocation Loc) {
+ PP.EnterToken(Tok, /*IsReinject*/ true);
+ PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true,
+ /*IsReinject*/ true);
+ // Consume the previously pushed token.
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
+
+ FNContextRAII FnContext(*this, Ptr);
+ // Parse function declaration id.
+ SourceLocation RLoc;
+ // Parse with IsAddressOfOperand set to true to parse methods as DeclRefExprs
+ // instead of MemberExprs.
+ ExprResult AssociatedFunction =
+ ParseOpenMPParensExpr(getOpenMPDirectiveName(OMPD_declare_variant), RLoc,
+ /*IsAddressOfOperand=*/true);
+ if (!AssociatedFunction.isUsable()) {
+ if (!Tok.is(tok::annot_pragma_openmp_end))
+ while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch))
+ ;
+ // Skip the last annot_pragma_openmp_end.
+ (void)ConsumeAnnotationToken();
+ return;
+ }
+ Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
+ Actions.checkOpenMPDeclareVariantFunction(
+ Ptr, AssociatedFunction.get(), SourceRange(Loc, Tok.getLocation()));
+
+ // Parse 'match'.
+ OpenMPClauseKind CKind = Tok.isAnnotation()
+ ? OMPC_unknown
+ : getOpenMPClauseKind(PP.getSpelling(Tok));
+ if (CKind != OMPC_match) {
+ Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause)
+ << getOpenMPClauseName(OMPC_match);
+ while (!SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch))
+ ;
+ // Skip the last annot_pragma_openmp_end.
+ (void)ConsumeAnnotationToken();
+ return;
+ }
+ (void)ConsumeToken();
+ // Parse '('.
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPClauseName(OMPC_match))) {
+ while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch))
+ ;
+ // Skip the last annot_pragma_openmp_end.
+ (void)ConsumeAnnotationToken();
+ return;
+ }
+
+ // Parse inner context selectors.
+ if (!parseOpenMPContextSelectors(
+ Loc, [this, &DeclVarData](
+ SourceRange SR,
+ const Sema::OpenMPDeclareVariantCtsSelectorData &Data) {
+ if (DeclVarData.hasValue())
+ Actions.ActOnOpenMPDeclareVariantDirective(
+ DeclVarData.getValue().first, DeclVarData.getValue().second,
+ SR, Data);
+ })) {
+ // Parse ')'.
+ (void)T.consumeClose();
+ // Need to check for extra tokens.
+ if (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
+ << getOpenMPDirectiveName(OMPD_declare_variant);
+ }
+ }
+
+ // Skip last tokens.
+ while (Tok.isNot(tok::annot_pragma_openmp_end))
+ ConsumeAnyToken();
+ // Skip the last annot_pragma_openmp_end.
+ (void)ConsumeAnnotationToken();
+}
+
+/// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.
+///
+/// default-clause:
+/// 'default' '(' 'none' | 'shared' ')
+///
+/// proc_bind-clause:
+/// 'proc_bind' '(' 'master' | 'close' | 'spread' ')
+///
+/// device_type-clause:
+/// 'device_type' '(' 'host' | 'nohost' | 'any' )'
+namespace {
+ struct SimpleClauseData {
+ unsigned Type;
+ SourceLocation Loc;
+ SourceLocation LOpen;
+ SourceLocation TypeLoc;
+ SourceLocation RLoc;
+ SimpleClauseData(unsigned Type, SourceLocation Loc, SourceLocation LOpen,
+ SourceLocation TypeLoc, SourceLocation RLoc)
+ : Type(Type), Loc(Loc), LOpen(LOpen), TypeLoc(TypeLoc), RLoc(RLoc) {}
+ };
+} // anonymous namespace
+
+static Optional<SimpleClauseData>
+parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) {
+ const Token &Tok = P.getCurToken();
+ SourceLocation Loc = Tok.getLocation();
+ SourceLocation LOpen = P.ConsumeToken();
+ // Parse '('.
+ BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPClauseName(Kind)))
+ return llvm::None;
+
+ unsigned Type = getOpenMPSimpleClauseType(
+ Kind, Tok.isAnnotation() ? "" : P.getPreprocessor().getSpelling(Tok));
+ SourceLocation TypeLoc = Tok.getLocation();
+ if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
+ Tok.isNot(tok::annot_pragma_openmp_end))
+ P.ConsumeAnyToken();
+
+ // Parse ')'.
+ SourceLocation RLoc = Tok.getLocation();
+ if (!T.consumeClose())
+ RLoc = T.getCloseLocation();
+
+ return SimpleClauseData(Type, Loc, LOpen, TypeLoc, RLoc);
+}
+
Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() {
// OpenMP 4.5 syntax with list of entities.
Sema::NamedDeclSetType SameDirectiveDecls;
+ SmallVector<std::tuple<OMPDeclareTargetDeclAttr::MapTypeTy, SourceLocation,
+ NamedDecl *>,
+ 4>
+ DeclareTargetDecls;
+ OMPDeclareTargetDeclAttr::DevTypeTy DT = OMPDeclareTargetDeclAttr::DT_Any;
+ SourceLocation DeviceTypeLoc;
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
OMPDeclareTargetDeclAttr::MapTypeTy MT = OMPDeclareTargetDeclAttr::MT_To;
if (Tok.is(tok::identifier)) {
IdentifierInfo *II = Tok.getIdentifierInfo();
StringRef ClauseName = II->getName();
- // Parse 'to|link' clauses.
- if (!OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT)) {
- Diag(Tok, diag::err_omp_declare_target_unexpected_clause) << ClauseName;
+ bool IsDeviceTypeClause =
+ getLangOpts().OpenMP >= 50 &&
+ getOpenMPClauseKind(ClauseName) == OMPC_device_type;
+ // Parse 'to|link|device_type' clauses.
+ if (!OMPDeclareTargetDeclAttr::ConvertStrToMapTypeTy(ClauseName, MT) &&
+ !IsDeviceTypeClause) {
+ Diag(Tok, diag::err_omp_declare_target_unexpected_clause)
+ << ClauseName << (getLangOpts().OpenMP >= 50 ? 1 : 0);
break;
}
+ // Parse 'device_type' clause and go to next clause if any.
+ if (IsDeviceTypeClause) {
+ Optional<SimpleClauseData> DevTypeData =
+ parseOpenMPSimpleClause(*this, OMPC_device_type);
+ if (DevTypeData.hasValue()) {
+ if (DeviceTypeLoc.isValid()) {
+ // We already saw another device_type clause, diagnose it.
+ Diag(DevTypeData.getValue().Loc,
+ diag::warn_omp_more_one_device_type_clause);
+ }
+ switch(static_cast<OpenMPDeviceType>(DevTypeData.getValue().Type)) {
+ case OMPC_DEVICE_TYPE_any:
+ DT = OMPDeclareTargetDeclAttr::DT_Any;
+ break;
+ case OMPC_DEVICE_TYPE_host:
+ DT = OMPDeclareTargetDeclAttr::DT_Host;
+ break;
+ case OMPC_DEVICE_TYPE_nohost:
+ DT = OMPDeclareTargetDeclAttr::DT_NoHost;
+ break;
+ case OMPC_DEVICE_TYPE_unknown:
+ llvm_unreachable("Unexpected device_type");
+ }
+ DeviceTypeLoc = DevTypeData.getValue().Loc;
+ }
+ continue;
+ }
ConsumeToken();
}
- auto &&Callback = [this, MT, &SameDirectiveDecls](
- CXXScopeSpec &SS, DeclarationNameInfo NameInfo) {
- Actions.ActOnOpenMPDeclareTargetName(getCurScope(), SS, NameInfo, MT,
- SameDirectiveDecls);
+ auto &&Callback = [this, MT, &DeclareTargetDecls, &SameDirectiveDecls](
+ CXXScopeSpec &SS, DeclarationNameInfo NameInfo) {
+ NamedDecl *ND = Actions.lookupOpenMPDeclareTargetName(
+ getCurScope(), SS, NameInfo, SameDirectiveDecls);
+ if (ND)
+ DeclareTargetDecls.emplace_back(MT, NameInfo.getLoc(), ND);
};
if (ParseOpenMPSimpleVarList(OMPD_declare_target, Callback,
/*AllowScopeSpecifier=*/true))
@@ -812,6 +1183,15 @@ Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() {
}
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
ConsumeAnyToken();
+ for (auto &MTLocDecl : DeclareTargetDecls) {
+ OMPDeclareTargetDeclAttr::MapTypeTy MT;
+ SourceLocation Loc;
+ NamedDecl *ND;
+ std::tie(MT, Loc, ND) = MTLocDecl;
+ // device_type clause is applied only to functions.
+ Actions.ActOnOpenMPDeclareTargetName(
+ ND, Loc, MT, isa<VarDecl>(ND) ? OMPDeclareTargetDeclAttr::DT_Any : DT);
+ }
SmallVector<Decl *, 4> Decls(SameDirectiveDecls.begin(),
SameDirectiveDecls.end());
if (Decls.empty())
@@ -1005,13 +1385,15 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
}
break;
}
+ case OMPD_declare_variant:
case OMPD_declare_simd: {
// The syntax is:
- // { #pragma omp declare simd }
+ // { #pragma omp declare {simd|variant} }
// <function-declaration-or-definition>
//
- ConsumeToken();
CachedTokens Toks;
+ Toks.push_back(Tok);
+ ConsumeToken();
while(Tok.isNot(tok::annot_pragma_openmp_end)) {
Toks.push_back(Tok);
ConsumeAnyToken();
@@ -1035,10 +1417,16 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
}
}
if (!Ptr) {
- Diag(Loc, diag::err_omp_decl_in_declare_simd);
+ Diag(Loc, diag::err_omp_decl_in_declare_simd_variant)
+ << (DKind == OMPD_declare_simd ? 0 : 1);
return DeclGroupPtrTy();
}
- return ParseOMPDeclareSimdClauses(Ptr, Toks, Loc);
+ if (DKind == OMPD_declare_simd)
+ return ParseOMPDeclareSimdClauses(Ptr, Toks, Loc);
+ assert(DKind == OMPD_declare_variant &&
+ "Expected declare variant directive only");
+ ParseOMPDeclareVariantClauses(Ptr, Toks, Loc);
+ return Ptr;
}
case OMPD_declare_target: {
SourceLocation DTLoc = ConsumeAnyToken();
@@ -1120,6 +1508,9 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
case OMPD_target_parallel_for:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_distribute:
case OMPD_end_declare_target:
case OMPD_target_update:
@@ -1174,20 +1565,17 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
/// 'parallel for' | 'parallel sections' | 'task' | 'taskyield' |
/// 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'atomic' |
/// 'for simd' | 'parallel for simd' | 'target' | 'target data' |
-/// 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' |
-/// 'distribute' | 'target enter data' | 'target exit data' |
-/// 'target parallel' | 'target parallel for' |
-/// 'target update' | 'distribute parallel for' |
-/// 'distribute paralle for simd' | 'distribute simd' |
-/// 'target parallel for simd' | 'target simd' |
-/// 'teams distribute' | 'teams distribute simd' |
-/// 'teams distribute parallel for simd' |
-/// 'teams distribute parallel for' | 'target teams' |
-/// 'target teams distribute' |
-/// 'target teams distribute parallel for' |
-/// 'target teams distribute parallel for simd' |
-/// 'target teams distribute simd' {clause}
-/// annot_pragma_openmp_end
+/// 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' | 'master
+/// taskloop' | 'master taskloop simd' | 'parallel master taskloop' |
+/// 'distribute' | 'target enter data' | 'target exit data' | 'target
+/// parallel' | 'target parallel for' | 'target update' | 'distribute
+/// parallel for' | 'distribute paralle for simd' | 'distribute simd' |
+/// 'target parallel for simd' | 'target simd' | 'teams distribute' |
+/// 'teams distribute simd' | 'teams distribute parallel for simd' |
+/// 'teams distribute parallel for' | 'target teams' | 'target teams
+/// distribute' | 'target teams distribute parallel for' | 'target teams
+/// distribute parallel for simd' | 'target teams distribute simd'
+/// {clause} annot_pragma_openmp_end
///
StmtResult
Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
@@ -1362,6 +1750,9 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
case OMPD_target_parallel_for:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_distribute:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
@@ -1474,6 +1865,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) {
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_requires:
+ case OMPD_declare_variant:
Diag(Tok, diag::err_omp_unexpected_directive)
<< 1 << getOpenMPDirectiveName(DKind);
SkipUntil(tok::annot_pragma_openmp_end);
@@ -1712,6 +2104,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_allocate:
Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective);
break;
+ case OMPC_device_type:
case OMPC_unknown:
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
<< getOpenMPDirectiveName(DKind);
@@ -1719,6 +2112,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
break;
case OMPC_threadprivate:
case OMPC_uniform:
+ case OMPC_match:
if (!WrongDirective)
Diag(Tok, diag::err_omp_unexpected_clause)
<< getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
@@ -1732,14 +2126,15 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
/// constructs.
/// \param RLoc Returned location of right paren.
ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName,
- SourceLocation &RLoc) {
+ SourceLocation &RLoc,
+ bool IsAddressOfOperand) {
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
if (T.expectAndConsume(diag::err_expected_lparen_after, ClauseName.data()))
return ExprError();
SourceLocation ELoc = Tok.getLocation();
ExprResult LHS(ParseCastExpression(
- /*isUnaryExpression=*/false, /*isAddressOfOperand=*/false, NotTypeCast));
+ /*isUnaryExpression=*/false, IsAddressOfOperand, NotTypeCast));
ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false);
@@ -1811,29 +2206,12 @@ OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind,
///
OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind,
bool ParseOnly) {
- SourceLocation Loc = Tok.getLocation();
- SourceLocation LOpen = ConsumeToken();
- // Parse '('.
- BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
- if (T.expectAndConsume(diag::err_expected_lparen_after,
- getOpenMPClauseName(Kind)))
- return nullptr;
-
- unsigned Type = getOpenMPSimpleClauseType(
- Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok));
- SourceLocation TypeLoc = Tok.getLocation();
- if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
- Tok.isNot(tok::annot_pragma_openmp_end))
- ConsumeAnyToken();
-
- // Parse ')'.
- SourceLocation RLoc = Tok.getLocation();
- if (!T.consumeClose())
- RLoc = T.getCloseLocation();
-
- if (ParseOnly)
+ llvm::Optional<SimpleClauseData> Val = parseOpenMPSimpleClause(*this, Kind);
+ if (!Val || ParseOnly)
return nullptr;
- return Actions.ActOnOpenMPSimpleClause(Kind, Type, TypeLoc, LOpen, Loc, RLoc);
+ return Actions.ActOnOpenMPSimpleClause(
+ Kind, Val.getValue().Type, Val.getValue().TypeLoc, Val.getValue().LOpen,
+ Val.getValue().Loc, Val.getValue().RLoc);
}
/// Parsing of OpenMP clauses like 'ordered'.
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index f81ecc738c28..cdbf697cf7f1 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -265,122 +265,122 @@ struct PragmaAttributeHandler : public PragmaHandler {
} // end namespace
void Parser::initializePragmaHandlers() {
- AlignHandler = llvm::make_unique<PragmaAlignHandler>();
+ AlignHandler = std::make_unique<PragmaAlignHandler>();
PP.AddPragmaHandler(AlignHandler.get());
- GCCVisibilityHandler = llvm::make_unique<PragmaGCCVisibilityHandler>();
+ GCCVisibilityHandler = std::make_unique<PragmaGCCVisibilityHandler>();
PP.AddPragmaHandler("GCC", GCCVisibilityHandler.get());
- OptionsHandler = llvm::make_unique<PragmaOptionsHandler>();
+ OptionsHandler = std::make_unique<PragmaOptionsHandler>();
PP.AddPragmaHandler(OptionsHandler.get());
- PackHandler = llvm::make_unique<PragmaPackHandler>();
+ PackHandler = std::make_unique<PragmaPackHandler>();
PP.AddPragmaHandler(PackHandler.get());
- MSStructHandler = llvm::make_unique<PragmaMSStructHandler>();
+ MSStructHandler = std::make_unique<PragmaMSStructHandler>();
PP.AddPragmaHandler(MSStructHandler.get());
- UnusedHandler = llvm::make_unique<PragmaUnusedHandler>();
+ UnusedHandler = std::make_unique<PragmaUnusedHandler>();
PP.AddPragmaHandler(UnusedHandler.get());
- WeakHandler = llvm::make_unique<PragmaWeakHandler>();
+ WeakHandler = std::make_unique<PragmaWeakHandler>();
PP.AddPragmaHandler(WeakHandler.get());
- RedefineExtnameHandler = llvm::make_unique<PragmaRedefineExtnameHandler>();
+ RedefineExtnameHandler = std::make_unique<PragmaRedefineExtnameHandler>();
PP.AddPragmaHandler(RedefineExtnameHandler.get());
- FPContractHandler = llvm::make_unique<PragmaFPContractHandler>();
+ FPContractHandler = std::make_unique<PragmaFPContractHandler>();
PP.AddPragmaHandler("STDC", FPContractHandler.get());
- STDCFENVHandler = llvm::make_unique<PragmaSTDC_FENV_ACCESSHandler>();
+ STDCFENVHandler = std::make_unique<PragmaSTDC_FENV_ACCESSHandler>();
PP.AddPragmaHandler("STDC", STDCFENVHandler.get());
- STDCCXLIMITHandler = llvm::make_unique<PragmaSTDC_CX_LIMITED_RANGEHandler>();
+ STDCCXLIMITHandler = std::make_unique<PragmaSTDC_CX_LIMITED_RANGEHandler>();
PP.AddPragmaHandler("STDC", STDCCXLIMITHandler.get());
- STDCUnknownHandler = llvm::make_unique<PragmaSTDC_UnknownHandler>();
+ STDCUnknownHandler = std::make_unique<PragmaSTDC_UnknownHandler>();
PP.AddPragmaHandler("STDC", STDCUnknownHandler.get());
- PCSectionHandler = llvm::make_unique<PragmaClangSectionHandler>(Actions);
+ PCSectionHandler = std::make_unique<PragmaClangSectionHandler>(Actions);
PP.AddPragmaHandler("clang", PCSectionHandler.get());
if (getLangOpts().OpenCL) {
- OpenCLExtensionHandler = llvm::make_unique<PragmaOpenCLExtensionHandler>();
+ OpenCLExtensionHandler = std::make_unique<PragmaOpenCLExtensionHandler>();
PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get());
PP.AddPragmaHandler("OPENCL", FPContractHandler.get());
}
if (getLangOpts().OpenMP)
- OpenMPHandler = llvm::make_unique<PragmaOpenMPHandler>();
+ OpenMPHandler = std::make_unique<PragmaOpenMPHandler>();
else
- OpenMPHandler = llvm::make_unique<PragmaNoOpenMPHandler>();
+ OpenMPHandler = std::make_unique<PragmaNoOpenMPHandler>();
PP.AddPragmaHandler(OpenMPHandler.get());
if (getLangOpts().MicrosoftExt ||
getTargetInfo().getTriple().isOSBinFormatELF()) {
- MSCommentHandler = llvm::make_unique<PragmaCommentHandler>(Actions);
+ MSCommentHandler = std::make_unique<PragmaCommentHandler>(Actions);
PP.AddPragmaHandler(MSCommentHandler.get());
}
if (getLangOpts().MicrosoftExt) {
MSDetectMismatchHandler =
- llvm::make_unique<PragmaDetectMismatchHandler>(Actions);
+ std::make_unique<PragmaDetectMismatchHandler>(Actions);
PP.AddPragmaHandler(MSDetectMismatchHandler.get());
- MSPointersToMembers = llvm::make_unique<PragmaMSPointersToMembers>();
+ MSPointersToMembers = std::make_unique<PragmaMSPointersToMembers>();
PP.AddPragmaHandler(MSPointersToMembers.get());
- MSVtorDisp = llvm::make_unique<PragmaMSVtorDisp>();
+ MSVtorDisp = std::make_unique<PragmaMSVtorDisp>();
PP.AddPragmaHandler(MSVtorDisp.get());
- MSInitSeg = llvm::make_unique<PragmaMSPragma>("init_seg");
+ MSInitSeg = std::make_unique<PragmaMSPragma>("init_seg");
PP.AddPragmaHandler(MSInitSeg.get());
- MSDataSeg = llvm::make_unique<PragmaMSPragma>("data_seg");
+ MSDataSeg = std::make_unique<PragmaMSPragma>("data_seg");
PP.AddPragmaHandler(MSDataSeg.get());
- MSBSSSeg = llvm::make_unique<PragmaMSPragma>("bss_seg");
+ MSBSSSeg = std::make_unique<PragmaMSPragma>("bss_seg");
PP.AddPragmaHandler(MSBSSSeg.get());
- MSConstSeg = llvm::make_unique<PragmaMSPragma>("const_seg");
+ MSConstSeg = std::make_unique<PragmaMSPragma>("const_seg");
PP.AddPragmaHandler(MSConstSeg.get());
- MSCodeSeg = llvm::make_unique<PragmaMSPragma>("code_seg");
+ MSCodeSeg = std::make_unique<PragmaMSPragma>("code_seg");
PP.AddPragmaHandler(MSCodeSeg.get());
- MSSection = llvm::make_unique<PragmaMSPragma>("section");
+ MSSection = std::make_unique<PragmaMSPragma>("section");
PP.AddPragmaHandler(MSSection.get());
- MSRuntimeChecks = llvm::make_unique<PragmaMSRuntimeChecksHandler>();
+ MSRuntimeChecks = std::make_unique<PragmaMSRuntimeChecksHandler>();
PP.AddPragmaHandler(MSRuntimeChecks.get());
- MSIntrinsic = llvm::make_unique<PragmaMSIntrinsicHandler>();
+ MSIntrinsic = std::make_unique<PragmaMSIntrinsicHandler>();
PP.AddPragmaHandler(MSIntrinsic.get());
- MSOptimize = llvm::make_unique<PragmaMSOptimizeHandler>();
+ MSOptimize = std::make_unique<PragmaMSOptimizeHandler>();
PP.AddPragmaHandler(MSOptimize.get());
}
if (getLangOpts().CUDA) {
CUDAForceHostDeviceHandler =
- llvm::make_unique<PragmaForceCUDAHostDeviceHandler>(Actions);
+ std::make_unique<PragmaForceCUDAHostDeviceHandler>(Actions);
PP.AddPragmaHandler("clang", CUDAForceHostDeviceHandler.get());
}
- OptimizeHandler = llvm::make_unique<PragmaOptimizeHandler>(Actions);
+ OptimizeHandler = std::make_unique<PragmaOptimizeHandler>(Actions);
PP.AddPragmaHandler("clang", OptimizeHandler.get());
- LoopHintHandler = llvm::make_unique<PragmaLoopHintHandler>();
+ LoopHintHandler = std::make_unique<PragmaLoopHintHandler>();
PP.AddPragmaHandler("clang", LoopHintHandler.get());
- UnrollHintHandler = llvm::make_unique<PragmaUnrollHintHandler>("unroll");
+ UnrollHintHandler = std::make_unique<PragmaUnrollHintHandler>("unroll");
PP.AddPragmaHandler(UnrollHintHandler.get());
- NoUnrollHintHandler = llvm::make_unique<PragmaUnrollHintHandler>("nounroll");
+ NoUnrollHintHandler = std::make_unique<PragmaUnrollHintHandler>("nounroll");
PP.AddPragmaHandler(NoUnrollHintHandler.get());
UnrollAndJamHintHandler =
- llvm::make_unique<PragmaUnrollHintHandler>("unroll_and_jam");
+ std::make_unique<PragmaUnrollHintHandler>("unroll_and_jam");
PP.AddPragmaHandler(UnrollAndJamHintHandler.get());
NoUnrollAndJamHintHandler =
- llvm::make_unique<PragmaUnrollHintHandler>("nounroll_and_jam");
+ std::make_unique<PragmaUnrollHintHandler>("nounroll_and_jam");
PP.AddPragmaHandler(NoUnrollAndJamHintHandler.get());
- FPHandler = llvm::make_unique<PragmaFPHandler>();
+ FPHandler = std::make_unique<PragmaFPHandler>();
PP.AddPragmaHandler("clang", FPHandler.get());
AttributePragmaHandler =
- llvm::make_unique<PragmaAttributeHandler>(AttrFactory);
+ std::make_unique<PragmaAttributeHandler>(AttrFactory);
PP.AddPragmaHandler("clang", AttributePragmaHandler.get());
}
@@ -1006,18 +1006,13 @@ struct PragmaLoopHintInfo {
} // end anonymous namespace
static std::string PragmaLoopHintString(Token PragmaName, Token Option) {
- std::string PragmaString;
- if (PragmaName.getIdentifierInfo()->getName() == "loop") {
- PragmaString = "clang loop ";
- PragmaString += Option.getIdentifierInfo()->getName();
- } else if (PragmaName.getIdentifierInfo()->getName() == "unroll_and_jam") {
- PragmaString = "unroll_and_jam";
- } else {
- assert(PragmaName.getIdentifierInfo()->getName() == "unroll" &&
- "Unexpected pragma name");
- PragmaString = "unroll";
- }
- return PragmaString;
+ StringRef Str = PragmaName.getIdentifierInfo()->getName();
+ std::string ClangLoopStr = (llvm::Twine("clang loop ") + Str).str();
+ return llvm::StringSwitch<StringRef>(Str)
+ .Case("loop", ClangLoopStr)
+ .Case("unroll_and_jam", Str)
+ .Case("unroll", Str)
+ .Default("");
}
bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
@@ -1041,12 +1036,12 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
// Return a valid hint if pragma unroll or nounroll were specified
// without an argument.
- bool PragmaUnroll = PragmaNameInfo->getName() == "unroll";
- bool PragmaNoUnroll = PragmaNameInfo->getName() == "nounroll";
- bool PragmaUnrollAndJam = PragmaNameInfo->getName() == "unroll_and_jam";
- bool PragmaNoUnrollAndJam = PragmaNameInfo->getName() == "nounroll_and_jam";
- if (Toks.empty() && (PragmaUnroll || PragmaNoUnroll || PragmaUnrollAndJam ||
- PragmaNoUnrollAndJam)) {
+ auto IsLoopHint = llvm::StringSwitch<bool>(PragmaNameInfo->getName())
+ .Cases("unroll", "nounroll", "unroll_and_jam",
+ "nounroll_and_jam", true)
+ .Default(false);
+
+ if (Toks.empty() && IsLoopHint) {
ConsumeAnnotationToken();
Hint.Range = Info->PragmaName.getLocation();
return true;
@@ -1071,6 +1066,7 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
StateOption = llvm::StringSwitch<bool>(OptionInfo->getName())
.Case("vectorize", true)
.Case("interleave", true)
+ .Case("vectorize_predicate", true)
.Default(false) ||
OptionUnroll || OptionUnrollAndJam || OptionDistribute ||
OptionPipelineDisabled;
@@ -1472,9 +1468,9 @@ void Parser::HandlePragmaAttribute() {
if (Tok.getIdentifierInfo()) {
// If we suspect that this is an attribute suggest the use of
// '__attribute__'.
- if (ParsedAttr::getKind(Tok.getIdentifierInfo(), /*ScopeName=*/nullptr,
- ParsedAttr::AS_GNU) !=
- ParsedAttr::UnknownAttribute) {
+ if (ParsedAttr::getParsedKind(
+ Tok.getIdentifierInfo(), /*ScopeName=*/nullptr,
+ ParsedAttr::AS_GNU) != ParsedAttr::UnknownAttribute) {
SourceLocation InsertStartLoc = Tok.getLocation();
ConsumeToken();
if (Tok.is(tok::l_paren)) {
@@ -1508,7 +1504,7 @@ void Parser::HandlePragmaAttribute() {
ParsedAttr &Attribute = *Attrs.begin();
if (!Attribute.isSupportedByPragmaAttribute()) {
Diag(PragmaLoc, diag::err_pragma_attribute_unsupported_attribute)
- << Attribute.getName();
+ << Attribute;
SkipToEnd();
return;
}
@@ -1625,7 +1621,7 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP,
return;
}
- auto Toks = llvm::make_unique<Token[]>(1);
+ auto Toks = std::make_unique<Token[]>(1);
Toks[0].startToken();
Toks[0].setKind(tok::annot_pragma_vis);
Toks[0].setLocation(VisLoc);
@@ -1794,7 +1790,7 @@ void PragmaMSStructHandler::HandlePragma(Preprocessor &PP,
/*IsReinject=*/false);
}
-// #pragma clang section bss="abc" data="" rodata="def" text=""
+// #pragma clang section bss="abc" data="" rodata="def" text="" relro=""
void PragmaClangSectionHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducer Introducer,
Token &FirstToken) {
@@ -1816,6 +1812,8 @@ void PragmaClangSectionHandler::HandlePragma(Preprocessor &PP,
SecKind = Sema::PragmaClangSectionKind::PCSK_Data;
else if (SecType->isStr("rodata"))
SecKind = Sema::PragmaClangSectionKind::PCSK_Rodata;
+ else if (SecType->isStr("relro"))
+ SecKind = Sema::PragmaClangSectionKind::PCSK_Relro;
else if (SecType->isStr("text"))
SecKind = Sema::PragmaClangSectionKind::PCSK_Text;
else {
@@ -2241,7 +2239,7 @@ void PragmaOpenMPHandler::HandlePragma(Preprocessor &PP,
Tok.setLocation(EodLoc);
Pragma.push_back(Tok);
- auto Toks = llvm::make_unique<Token[]>(Pragma.size());
+ auto Toks = std::make_unique<Token[]>(Pragma.size());
std::copy(Pragma.begin(), Pragma.end(), Toks.get());
PP.EnterTokenStream(std::move(Toks), Pragma.size(),
/*DisableMacroExpansion=*/false, /*IsReinject=*/false);
@@ -2458,7 +2456,7 @@ void PragmaMSPragma::HandlePragma(Preprocessor &PP,
TokenVector.push_back(EoF);
// We must allocate this array with new because EnterTokenStream is going to
// delete it later.
- auto TokenArray = llvm::make_unique<Token[]>(TokenVector.size());
+ auto TokenArray = std::make_unique<Token[]>(TokenVector.size());
std::copy(TokenVector.begin(), TokenVector.end(), TokenArray.get());
auto Value = new (PP.getPreprocessorAllocator())
std::pair<std::unique_ptr<Token[]>, size_t>(std::move(TokenArray),
@@ -2743,7 +2741,7 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
return;
}
- auto TokenArray = llvm::make_unique<Token[]>(TokenList.size());
+ auto TokenArray = std::make_unique<Token[]>(TokenList.size());
std::copy(TokenList.begin(), TokenList.end(), TokenArray.get());
PP.EnterTokenStream(std::move(TokenArray), TokenList.size(),
@@ -2824,6 +2822,7 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName,
/// 'vectorize' '(' loop-hint-keyword ')'
/// 'interleave' '(' loop-hint-keyword ')'
/// 'unroll' '(' unroll-hint-keyword ')'
+/// 'vectorize_predicate' '(' loop-hint-keyword ')'
/// 'vectorize_width' '(' loop-hint-value ')'
/// 'interleave_count' '(' loop-hint-value ')'
/// 'unroll_count' '(' loop-hint-value ')'
@@ -2885,6 +2884,7 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
.Case("interleave", true)
.Case("unroll", true)
.Case("distribute", true)
+ .Case("vectorize_predicate", true)
.Case("vectorize_width", true)
.Case("interleave_count", true)
.Case("unroll_count", true)
@@ -2926,7 +2926,7 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
return;
}
- auto TokenArray = llvm::make_unique<Token[]>(TokenList.size());
+ auto TokenArray = std::make_unique<Token[]>(TokenList.size());
std::copy(TokenList.begin(), TokenList.end(), TokenArray.get());
PP.EnterTokenStream(std::move(TokenArray), TokenList.size(),
@@ -2998,7 +2998,7 @@ void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
}
// Generate the hint token.
- auto TokenArray = llvm::make_unique<Token[]>(1);
+ auto TokenArray = std::make_unique<Token[]>(1);
TokenArray[0].startToken();
TokenArray[0].setKind(tok::annot_pragma_loop_hint);
TokenArray[0].setLocation(PragmaName.getLocation());
@@ -3270,7 +3270,7 @@ void PragmaAttributeHandler::HandlePragma(Preprocessor &PP,
<< "clang attribute";
// Generate the annotated pragma token.
- auto TokenArray = llvm::make_unique<Token[]>(1);
+ auto TokenArray = std::make_unique<Token[]>(1);
TokenArray[0].startToken();
TokenArray[0].setKind(tok::annot_pragma_attribute);
TokenArray[0].setLocation(FirstToken.getLocation());
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index bf04253ab7fd..727ab75adae8 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -140,7 +140,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<StatementFilterCCC>(*this);
+ return std::make_unique<StatementFilterCCC>(*this);
}
private:
@@ -153,6 +153,7 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs) {
const char *SemiError = nullptr;
StmtResult Res;
+ SourceLocation GNUAttributeLoc;
// 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),
@@ -186,7 +187,7 @@ Retry:
// Try to limit which sets of keywords should be included in typo
// correction based on what the next token is.
StatementFilterCCC CCC(Next);
- if (TryAnnotateName(/*IsAddressOfOperand*/ false, &CCC) == ANK_Error) {
+ if (TryAnnotateName(&CCC) == ANK_Error) {
// Handle errors here by skipping up to the next semicolon or '}', and
// eat the semicolon if that's what stopped us.
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
@@ -208,10 +209,19 @@ Retry:
if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt ||
(StmtCtx & ParsedStmtContext::AllowDeclarationsInC) !=
ParsedStmtContext()) &&
- isDeclarationStatement()) {
+ (GNUAttributeLoc.isValid() || isDeclarationStatement())) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- DeclGroupPtrTy Decl = ParseDeclaration(DeclaratorContext::BlockContext,
- DeclEnd, Attrs);
+ DeclGroupPtrTy Decl;
+ if (GNUAttributeLoc.isValid()) {
+ DeclStart = GNUAttributeLoc;
+ Decl = ParseDeclaration(DeclaratorContext::BlockContext, DeclEnd, Attrs,
+ &GNUAttributeLoc);
+ } else {
+ Decl =
+ ParseDeclaration(DeclaratorContext::BlockContext, DeclEnd, Attrs);
+ }
+ if (Attrs.Range.getBegin().isValid())
+ DeclStart = Attrs.Range.getBegin();
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
}
@@ -223,6 +233,12 @@ Retry:
return ParseExprStatement(StmtCtx);
}
+ case tok::kw___attribute: {
+ GNUAttributeLoc = Tok.getLocation();
+ ParseGNUAttributes(Attrs);
+ goto Retry;
+ }
+
case tok::kw_case: // C99 6.8.1: labeled-statement
return ParseCaseStatement(StmtCtx);
case tok::kw_default: // C99 6.8.1: labeled-statement
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 9bb5b6eac37e..928bc5aa25b3 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -630,11 +630,11 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
}
// Grab the template parameter name (if given)
- SourceLocation NameLoc;
+ SourceLocation NameLoc = Tok.getLocation();
IdentifierInfo *ParamName = nullptr;
if (Tok.is(tok::identifier)) {
ParamName = Tok.getIdentifierInfo();
- NameLoc = ConsumeToken();
+ ConsumeToken();
} else if (Tok.isOneOf(tok::equal, tok::comma, tok::greater,
tok::greatergreater)) {
// Unnamed template parameter. Don't have to do anything here, just
@@ -727,11 +727,11 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
: diag::ext_variadic_templates);
// Get the identifier, if given.
- SourceLocation NameLoc;
+ SourceLocation NameLoc = Tok.getLocation();
IdentifierInfo *ParamName = nullptr;
if (Tok.is(tok::identifier)) {
ParamName = Tok.getIdentifierInfo();
- NameLoc = ConsumeToken();
+ ConsumeToken();
} else if (Tok.isOneOf(tok::equal, tok::comma, tok::greater,
tok::greatergreater)) {
// Unnamed template parameter. Don't have to do anything here, just
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index a413f9a94148..e2e16ca63d1e 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -1193,7 +1193,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<TentativeParseCCC>(*this);
+ return std::make_unique<TentativeParseCCC>(*this);
}
};
}
@@ -1330,7 +1330,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
// this is ambiguous. Typo-correct to type and expression keywords and
// to types and identifiers, in order to try to recover from errors.
TentativeParseCCC CCC(Next);
- switch (TryAnnotateName(false /* no nested name specifier */, &CCC)) {
+ switch (TryAnnotateName(&CCC)) {
case ANK_Error:
return TPResult::Error;
case ANK_TentativeDecl:
@@ -1408,6 +1408,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
case tok::kw_typedef:
case tok::kw_constexpr:
case tok::kw_consteval:
+ case tok::kw_constinit:
// storage-class-specifier
case tok::kw_register:
case tok::kw_static:
@@ -1568,7 +1569,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
} else {
// Try to resolve the name. If it doesn't exist, assume it was
// intended to name a type and keep disambiguating.
- switch (TryAnnotateName(false /* SS is not dependent */)) {
+ switch (TryAnnotateName()) {
case ANK_Error:
return TPResult::Error;
case ANK_TentativeDecl:
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 9124f1558664..2645f27e656f 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -174,7 +174,7 @@ bool Parser::ExpectAndConsumeSemi(unsigned DiagID) {
return ExpectAndConsume(tok::semi, DiagID);
}
-void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) {
+void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST TST) {
if (!Tok.is(tok::semi)) return;
bool HadMultipleSemis = false;
@@ -202,7 +202,7 @@ void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) {
if (Kind != AfterMemberFunctionDefinition || HadMultipleSemis)
Diag(StartLoc, diag::ext_extra_semi)
- << Kind << DeclSpec::getSpecifierName((DeclSpec::TST)TST,
+ << Kind << DeclSpec::getSpecifierName(TST,
Actions.getASTContext().getPrintingPolicy())
<< FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
else
@@ -1174,8 +1174,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (Tok.isNot(tok::equal)) {
for (const ParsedAttr &AL : D.getAttributes())
if (AL.isKnownToGCC() && !AL.isCXX11Attribute())
- Diag(AL.getLoc(), diag::warn_attribute_on_function_definition)
- << AL.getName();
+ Diag(AL.getLoc(), diag::warn_attribute_on_function_definition) << AL;
}
// In delayed template parsing mode, for function template we consume the
@@ -1562,13 +1561,10 @@ void Parser::AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation) {
/// with a typo-corrected keyword. This is only appropriate when the current
/// name must refer to an entity which has already been declared.
///
-/// \param IsAddressOfOperand Must be \c true if the name is preceded by an '&'
-/// and might possibly have a dependent nested name specifier.
/// \param CCC Indicates how to perform typo-correction for this name. If NULL,
/// no typo correction will be performed.
Parser::AnnotatedNameKind
-Parser::TryAnnotateName(bool IsAddressOfOperand,
- CorrectionCandidateCallback *CCC) {
+Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
assert(Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope));
const bool EnteringContext = false;
@@ -1604,9 +1600,8 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
// after a scope specifier, because in general we can't recover from typos
// there (eg, after correcting 'A::template B<X>::C' [sic], we would need to
// jump back into scope specifier parsing).
- Sema::NameClassification Classification =
- Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next,
- IsAddressOfOperand, SS.isEmpty() ? CCC : nullptr);
+ Sema::NameClassification Classification = Actions.ClassifyName(
+ getCurScope(), SS, Name, NameLoc, Next, SS.isEmpty() ? CCC : nullptr);
// If name lookup found nothing and we guessed that this was a template name,
// double-check before committing to that interpretation. C++20 requires that
@@ -1619,7 +1614,7 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
FakeNext.setKind(tok::unknown);
Classification =
Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, FakeNext,
- IsAddressOfOperand, SS.isEmpty() ? CCC : nullptr);
+ SS.isEmpty() ? CCC : nullptr);
}
switch (Classification.getKind()) {
@@ -1672,7 +1667,7 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
return ANK_Success;
}
- case Sema::NC_Expression:
+ case Sema::NC_ContextIndependentExpr:
Tok.setKind(tok::annot_primary_expr);
setExprAnnotation(Tok, Classification.getExpression());
Tok.setAnnotationEndLoc(NameLoc);
@@ -1681,6 +1676,29 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
PP.AnnotateCachedTokens(Tok);
return ANK_Success;
+ case Sema::NC_NonType:
+ Tok.setKind(tok::annot_non_type);
+ setNonTypeAnnotation(Tok, Classification.getNonTypeDecl());
+ Tok.setLocation(NameLoc);
+ Tok.setAnnotationEndLoc(NameLoc);
+ PP.AnnotateCachedTokens(Tok);
+ if (SS.isNotEmpty())
+ AnnotateScopeToken(SS, !WasScopeAnnotation);
+ return ANK_Success;
+
+ case Sema::NC_UndeclaredNonType:
+ case Sema::NC_DependentNonType:
+ Tok.setKind(Classification.getKind() == Sema::NC_UndeclaredNonType
+ ? tok::annot_non_type_undeclared
+ : tok::annot_non_type_dependent);
+ setIdentifierAnnotation(Tok, Name);
+ Tok.setLocation(NameLoc);
+ Tok.setAnnotationEndLoc(NameLoc);
+ PP.AnnotateCachedTokens(Tok);
+ if (SS.isNotEmpty())
+ AnnotateScopeToken(SS, !WasScopeAnnotation);
+ return ANK_Success;
+
case Sema::NC_TypeTemplate:
if (Next.isNot(tok::less)) {
// This may be a type template being used as a template template argument.
@@ -1702,9 +1720,6 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
return ANK_Error;
return ANK_Success;
}
-
- case Sema::NC_NestedNameSpecifier:
- llvm_unreachable("already parsed nested name specifier");
}
// Unable to classify the name, but maybe we can annotate a scope specifier.
diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Rewriter.cpp
index 881399e98e33..33718b7721ce 100644
--- a/lib/Rewrite/Rewriter.cpp
+++ b/lib/Rewrite/Rewriter.cpp
@@ -96,6 +96,17 @@ void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size,
}
if (posI != end() && *posI == '\n') {
Buffer.erase(curLineStartOffs, lineSize + 1/* + '\n'*/);
+ // FIXME: Here, the offset of the start of the line is supposed to be
+ // expressed in terms of the original input not the "real" rewrite
+ // buffer. How do we compute that reliably? It might be tempting to use
+ // curLineStartOffs + OrigOffset - RealOffset, but that assumes the
+ // difference between the original and real offset is the same at the
+ // removed text and at the start of the line, but that's not true if
+ // edits were previously made earlier on the line. This bug is also
+ // documented by a FIXME on the definition of
+ // clang::Rewriter::RewriteOptions::RemoveLineIfEmpty. A reproducer for
+ // the implementation below is the test RemoveLineIfEmpty in
+ // clang/unittests/Rewrite/RewriteBufferTest.cpp.
AddReplaceDelta(curLineStartOffs, -(lineSize + 1/* + '\n'*/));
}
}
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index ce01909f1858..2c70c0599ecf 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -159,6 +159,20 @@ public:
S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_always)
<< DiagRange << isAlwaysTrue;
}
+
+ void compareBitwiseOr(const BinaryOperator *B) override {
+ if (HasMacroID(B))
+ return;
+
+ SourceRange DiagRange = B->getSourceRange();
+ S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange;
+ }
+
+ static bool hasActiveDiagnostics(DiagnosticsEngine &Diags,
+ SourceLocation Loc) {
+ return !Diags.isIgnored(diag::warn_tautological_overlap_comparison, Loc) ||
+ !Diags.isIgnored(diag::warn_comparison_bitwise_or, Loc);
+ }
};
} // anonymous namespace
@@ -1215,7 +1229,7 @@ static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
tok::r_square, tok::r_square
};
- bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17;
+ bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17 && !PP.getLangOpts().C2x;
StringRef MacroName;
if (PreferClangAttr)
@@ -1224,24 +1238,19 @@ static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens);
if (MacroName.empty() && !PreferClangAttr)
MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens);
- if (MacroName.empty())
- MacroName = PreferClangAttr ? "[[clang::fallthrough]]" : "[[fallthrough]]";
+ if (MacroName.empty()) {
+ if (!PreferClangAttr)
+ MacroName = "[[fallthrough]]";
+ else if (PP.getLangOpts().CPlusPlus)
+ MacroName = "[[clang::fallthrough]]";
+ else
+ MacroName = "__attribute__((fallthrough))";
+ }
return MacroName;
}
static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
bool PerFunction) {
- // Only perform this analysis when using [[]] attributes. There is no good
- // workflow for this warning when not using C++11. There is no good way to
- // silence the warning (no attribute is available) unless we are using
- // [[]] attributes. One could use pragmas to silence the warning, but as a
- // general solution that is gross and not in the spirit of this warning.
- //
- // NOTE: This an intermediate solution. There are on-going discussions on
- // how to properly support this warning outside of C++11 with an annotation.
- if (!AC.getASTContext().getLangOpts().DoubleSquareBracketAttributes)
- return;
-
FallthroughMapper FM(S);
FM.TraverseStmt(AC.getBody());
@@ -1281,25 +1290,24 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
SourceLocation L = Label->getBeginLoc();
if (L.isMacroID())
continue;
- if (S.getLangOpts().CPlusPlus11) {
- const Stmt *Term = B->getTerminatorStmt();
- // Skip empty cases.
- while (B->empty() && !Term && B->succ_size() == 1) {
- B = *B->succ_begin();
- Term = B->getTerminatorStmt();
- }
- if (!(B->empty() && Term && isa<BreakStmt>(Term))) {
- Preprocessor &PP = S.getPreprocessor();
- StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L);
- SmallString<64> TextToInsert(AnnotationSpelling);
- TextToInsert += "; ";
- S.Diag(L, diag::note_insert_fallthrough_fixit) <<
- AnnotationSpelling <<
- FixItHint::CreateInsertion(L, TextToInsert);
- }
+
+ const Stmt *Term = B->getTerminatorStmt();
+ // Skip empty cases.
+ while (B->empty() && !Term && B->succ_size() == 1) {
+ B = *B->succ_begin();
+ Term = B->getTerminatorStmt();
+ }
+ if (!(B->empty() && Term && isa<BreakStmt>(Term))) {
+ Preprocessor &PP = S.getPreprocessor();
+ StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L);
+ SmallString<64> TextToInsert(AnnotationSpelling);
+ TextToInsert += "; ";
+ S.Diag(L, diag::note_insert_fallthrough_fixit)
+ << AnnotationSpelling
+ << FixItHint::CreateInsertion(L, TextToInsert);
}
- S.Diag(L, diag::note_insert_break_fixit) <<
- FixItHint::CreateInsertion(L, "break; ");
+ S.Diag(L, diag::note_insert_break_fixit)
+ << FixItHint::CreateInsertion(L, "break; ");
}
}
@@ -2076,10 +2084,9 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
.setAlwaysAdd(Stmt::AttributedStmtClass);
}
- // Install the logical handler for -Wtautological-overlap-compare
+ // Install the logical handler.
llvm::Optional<LogicalErrorHandler> LEH;
- if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison,
- D->getBeginLoc())) {
+ if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {
LEH.emplace(S);
AC.getCFGBuildOptions().Observer = &*LEH;
}
@@ -2228,9 +2235,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
checkThrowInNonThrowingFunc(S, FD, AC);
// If none of the previous checks caused a CFG build, trigger one here
- // for -Wtautological-overlap-compare
- if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison,
- D->getBeginLoc())) {
+ // for the logical error handler.
+ if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) {
AC.getCFG();
}
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 77e5eb095693..639231c87232 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -569,6 +569,7 @@ const char *DeclSpec::getSpecifierName(ConstexprSpecKind C) {
case CSK_unspecified: return "unspecified";
case CSK_constexpr: return "constexpr";
case CSK_consteval: return "consteval";
+ case CSK_constinit: return "constinit";
}
llvm_unreachable("Unknown ConstexprSpecKind");
}
@@ -1036,13 +1037,9 @@ bool DeclSpec::setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec,
bool DeclSpec::SetConstexprSpec(ConstexprSpecKind ConstexprKind,
SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID) {
- if (getConstexprSpecifier() != CSK_unspecified) {
- if (getConstexprSpecifier() == CSK_consteval || ConstexprKind == CSK_consteval)
- return BadSpecifier(ConstexprKind, getConstexprSpecifier(), PrevSpec, DiagID);
- DiagID = diag::warn_duplicate_declspec;
- PrevSpec = "constexpr";
- return true;
- }
+ if (getConstexprSpecifier() != CSK_unspecified)
+ return BadSpecifier(ConstexprKind, getConstexprSpecifier(), PrevSpec,
+ DiagID);
ConstexprSpecifier = ConstexprKind;
ConstexprLoc = Loc;
return false;
@@ -1291,8 +1288,10 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
<< (TypeSpecType == TST_char16 ? "char16_t" : "char32_t");
if (getConstexprSpecifier() == CSK_constexpr)
S.Diag(ConstexprLoc, diag::warn_cxx98_compat_constexpr);
- if (getConstexprSpecifier() == CSK_consteval)
+ else if (getConstexprSpecifier() == CSK_consteval)
S.Diag(ConstexprLoc, diag::warn_cxx20_compat_consteval);
+ else if (getConstexprSpecifier() == CSK_constinit)
+ S.Diag(ConstexprLoc, diag::warn_cxx20_compat_constinit);
// C++ [class.friend]p6:
// No storage-class-specifier shall appear in the decl-specifier-seq
// of a friend declaration.
diff --git a/lib/Sema/OpenCLBuiltins.td b/lib/Sema/OpenCLBuiltins.td
index 7e37e55dbafa..298614059467 100644
--- a/lib/Sema/OpenCLBuiltins.td
+++ b/lib/Sema/OpenCLBuiltins.td
@@ -20,75 +20,164 @@
//===----------------------------------------------------------------------===//
// Versions of OpenCL
class Version<int _Version> {
- int Version = _Version;
+ int ID = _Version;
}
-def CL10: Version<100>;
-def CL11: Version<110>;
-def CL12: Version<120>;
-def CL20: Version<200>;
+def CLAll : Version< 0>;
+def CL10 : Version<100>;
+def CL11 : Version<110>;
+def CL12 : Version<120>;
+def CL20 : Version<200>;
// Address spaces
// Pointer types need to be assigned an address space.
class AddressSpace<string _AS> {
- string AddrSpace = _AS;
+ string Name = _AS;
}
-def default_as : AddressSpace<"clang::LangAS::Default">;
-def private_as : AddressSpace<"clang::LangAS::opencl_private">;
-def global_as : AddressSpace<"clang::LangAS::opencl_global">;
-def constant_as : AddressSpace<"clang::LangAS::opencl_constant">;
-def local_as : AddressSpace<"clang::LangAS::opencl_local">;
-def generic_as : AddressSpace<"clang::LangAS::opencl_generic">;
+def DefaultAS : AddressSpace<"clang::LangAS::Default">;
+def PrivateAS : AddressSpace<"clang::LangAS::opencl_private">;
+def GlobalAS : AddressSpace<"clang::LangAS::opencl_global">;
+def ConstantAS : AddressSpace<"clang::LangAS::opencl_constant">;
+def LocalAS : AddressSpace<"clang::LangAS::opencl_local">;
+def GenericAS : AddressSpace<"clang::LangAS::opencl_generic">;
-// Qualified Type. Allow to retrieve one ASTContext QualType.
-class QualType<string _Name> {
+// Qualified Type. These map to ASTContext::QualType.
+class QualType<string _Name, bit _IsAbstract=0> {
// Name of the field or function in a clang::ASTContext
// E.g. Name="IntTy" for the int type, and "getIntPtrType()" for an intptr_t
string Name = _Name;
+ // Some QualTypes in this file represent an abstract type for which there is
+ // no corresponding AST QualType, e.g. a GenType or an `image2d_t` type
+ // without access qualifiers.
+ bit IsAbstract = _IsAbstract;
}
-// Helper class to store type access qualifiers (volatile, const, ...).
-class Qualifier<string _QualName> {
- string QualName = _QualName;
+// List of integers.
+class IntList<string _Name, list<int> _List> {
+ string Name = _Name;
+ list<int> List = _List;
}
//===----------------------------------------------------------------------===//
// OpenCL C classes for types
//===----------------------------------------------------------------------===//
-// OpenCL types (int, float, ...)
+// OpenCL C basic data types (int, float, image2d_t, ...).
+// Its child classes can represent concrete types (e.g. VectorType) or
+// abstract types (e.g. GenType).
class Type<string _Name, QualType _QTName> {
- // Name of the Type
+ // Name of the Type.
string Name = _Name;
- // QualType associated with this type
+ // QualType associated with this type.
QualType QTName = _QTName;
- // Size of the vector (if applicable)
- int VecWidth = 0;
- // Is pointer
+ // Size of the vector (if applicable).
+ int VecWidth = 1;
+ // Is a pointer.
bit IsPointer = 0;
- // List of qualifiers associated with the type (volatile, ...)
- list<Qualifier> QualList = [];
- // Address space
- string AddrSpace = "clang::LangAS::Default";
+ // "const" qualifier.
+ bit IsConst = 0;
+ // "volatile" qualifier.
+ bit IsVolatile = 0;
// Access qualifier. Must be one of ("RO", "WO", "RW").
string AccessQualifier = "";
+ // Address space.
+ string AddrSpace = DefaultAS.Name;
}
-// OpenCL vector types (e.g. int2, int3, int16, float8, ...)
+// OpenCL vector types (e.g. int2, int3, int16, float8, ...).
class VectorType<Type _Ty, int _VecWidth> : Type<_Ty.Name, _Ty.QTName> {
- int VecWidth = _VecWidth;
+ let VecWidth = _VecWidth;
+ let AccessQualifier = "";
+ // Inherited fields
+ let IsPointer = _Ty.IsPointer;
+ let IsConst = _Ty.IsConst;
+ let IsVolatile = _Ty.IsVolatile;
+ let AddrSpace = _Ty.AddrSpace;
}
-// OpenCL pointer types (e.g. int*, float*, ...)
-class PointerType<Type _Ty, AddressSpace _AS = global_as> :
+// OpenCL pointer types (e.g. int*, float*, ...).
+class PointerType<Type _Ty, AddressSpace _AS = DefaultAS> :
Type<_Ty.Name, _Ty.QTName> {
- bit IsPointer = 1;
- string AddrSpace = _AS.AddrSpace;
+ let AddrSpace = _AS.Name;
+ // Inherited fields
+ let VecWidth = _Ty.VecWidth;
+ let IsPointer = 1;
+ let IsConst = _Ty.IsConst;
+ let IsVolatile = _Ty.IsVolatile;
+ let AccessQualifier = _Ty.AccessQualifier;
+}
+
+// OpenCL const types (e.g. const int).
+class ConstType<Type _Ty> : Type<_Ty.Name, _Ty.QTName> {
+ let IsConst = 1;
+ // Inherited fields
+ let VecWidth = _Ty.VecWidth;
+ let IsPointer = _Ty.IsPointer;
+ let IsVolatile = _Ty.IsVolatile;
+ let AccessQualifier = _Ty.AccessQualifier;
+ let AddrSpace = _Ty.AddrSpace;
+}
+
+// OpenCL volatile types (e.g. volatile int).
+class VolatileType<Type _Ty> : Type<_Ty.Name, _Ty.QTName> {
+ let IsVolatile = 1;
+ // Inherited fields
+ let VecWidth = _Ty.VecWidth;
+ let IsPointer = _Ty.IsPointer;
+ let IsConst = _Ty.IsConst;
+ let AccessQualifier = _Ty.AccessQualifier;
+ let AddrSpace = _Ty.AddrSpace;
}
-// OpenCL image types (e.g. image2d_t, ...)
-class ImageType<Type _Ty, QualType _QTName, string _AccessQualifier> :
- Type<_Ty.Name, _QTName> {
+// OpenCL image types (e.g. image2d).
+class ImageType<Type _Ty, string _AccessQualifier> :
+ Type<_Ty.Name, QualType<_Ty.QTName.Name#_AccessQualifier#"Ty", 0>> {
+ let VecWidth = 0;
let AccessQualifier = _AccessQualifier;
+ // Inherited fields
+ let IsPointer = _Ty.IsPointer;
+ let IsConst = _Ty.IsConst;
+ let IsVolatile = _Ty.IsVolatile;
+ let AddrSpace = _Ty.AddrSpace;
+}
+
+// List of Types.
+class TypeList<string _Name, list<Type> _Type> {
+ string Name = _Name;
+ list<Type> List = _Type;
+}
+
+// A GenericType is an abstract type that defines a set of types as a
+// combination of Types and vector sizes.
+//
+// For example, if TypeList = <int, float> and VectorList = <1, 2, 4>, then it
+// represents <int, int2, int4, float, float2, float4>.
+//
+// Some rules apply when using multiple GenericType arguments in a declaration:
+// 1. The number of vector sizes must be equal or 1 for all gentypes in a
+// declaration.
+// 2. The number of Types must be equal or 1 for all gentypes in a
+// declaration.
+// 3. Generic types are combined by iterating over all generic types at once.
+// For example, for the following GenericTypes
+// GenT1 = GenericType<half, [1, 2]> and
+// GenT2 = GenericType<float, int, [1, 2]>
+// A declaration f(GenT1, GenT2) results in the combinations
+// f(half, float), f(half2, float2), f(half, int), f(half2, int2) .
+// 4. "sgentype" from the OpenCL specification is supported by specifying
+// a single vector size.
+// For example, for the following GenericTypes
+// GenT = GenericType<half, int, [1, 2]> and
+// SGenT = GenericType<half, int, [1]>
+// A declaration f(GenT, SGenT) results in the combinations
+// f(half, half), f(half2, half), f(int, int), f(int2, int) .
+class GenericType<string _Ty, TypeList _TypeList, IntList _VectorList> :
+ Type<_Ty, QualType<"null", 1>> {
+ // Possible element types of the generic type.
+ TypeList TypeList = _TypeList;
+ // Possible vector sizes of the types in the TypeList.
+ IntList VectorList = _VectorList;
+ // The VecWidth field is ignored for GenericTypes. Use VectorList instead.
+ let VecWidth = 0;
}
//===----------------------------------------------------------------------===//
@@ -103,141 +192,124 @@ class Builtin<string _Name, list<Type> _Signature> {
list<Type> Signature = _Signature;
// OpenCL Extension to which the function belongs (cl_khr_subgroups, ...)
string Extension = "";
- // OpenCL Version to which the function belongs (CL10, ...)
- Version Version = CL10;
+ // Version of OpenCL from which the function is available (e.g.: CL10).
+ // MinVersion is inclusive.
+ Version MinVersion = CL10;
+ // Version of OpenCL from which the function is not supported anymore.
+ // MaxVersion is exclusive.
+ // CLAll makes the function available for all versions.
+ Version MaxVersion = CLAll;
}
//===----------------------------------------------------------------------===//
-// Multiclass definitions
+// Definitions of OpenCL C types
//===----------------------------------------------------------------------===//
-// multiclass BifN: Creates Builtin class instances for OpenCL builtin
-// functions with N arguments.
-// _Name : Name of the function
-// _Signature : Signature of the function (list of the Type used by the
-// function, the first one being the return type).
-// _IsVector : List of bit indicating if the type in the _Signature at the
-// same index is to be a vector in the multiple overloads. The
-// list must have at least one non-zero value.
-multiclass Bif0<string _Name, list<Type> _Signature, list<bit> _IsVector> {
- def : Builtin<_Name, _Signature>;
- foreach v = [2, 3, 4, 8, 16] in {
- def : Builtin<_Name,
- [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0])]>;
- }
-}
-multiclass Bif1<string _Name, list<Type> _Signature, list<bit> _IsVector> {
- def : Builtin<_Name, _Signature>;
- foreach v = [2, 3, 4, 8, 16] in {
- def : Builtin<_Name,
- [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0]),
- !if(_IsVector[1], VectorType<_Signature[1], v>, _Signature[1])]>;
- }
-}
-multiclass Bif2<string _Name, list<Type> _Signature, list<bit> _IsVector> {
- def : Builtin<_Name, _Signature>;
- foreach v = [2, 3, 4, 8, 16] in {
- def : Builtin<_Name,
- [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0]),
- !if(_IsVector[1], VectorType<_Signature[1], v>, _Signature[1]),
- !if(_IsVector[2], VectorType<_Signature[2], v>, _Signature[2])]>;
- }
-}
-multiclass Bif3<string _Name, list<Type> _Signature, list<bit> _IsVector> {
- def : Builtin<_Name, _Signature>;
- foreach v = [2, 3, 4, 8, 16] in {
- def : Builtin<_Name,
- [!if(_IsVector[0], VectorType<_Signature[0], v>, _Signature[0]),
- !if(_IsVector[1], VectorType<_Signature[1], v>, _Signature[1]),
- !if(_IsVector[2], VectorType<_Signature[2], v>, _Signature[2]),
- !if(_IsVector[3], VectorType<_Signature[3], v>, _Signature[3])]>;
- }
-}
+
+// OpenCL v1.0/1.2/2.0 s6.1.1: Built-in Scalar Data Types.
+def Bool : Type<"bool", QualType<"BoolTy">>;
+def Char : Type<"char", QualType<"CharTy">>;
+def UChar : Type<"uchar", QualType<"UnsignedCharTy">>;
+def Short : Type<"short", QualType<"ShortTy">>;
+def UShort : Type<"ushort", QualType<"UnsignedShortTy">>;
+def Int : Type<"int", QualType<"IntTy">>;
+def UInt : Type<"uint", QualType<"UnsignedIntTy">>;
+def Long : Type<"long", QualType<"LongTy">>;
+def ULong : Type<"ulong", QualType<"UnsignedLongTy">>;
+def Float : Type<"float", QualType<"FloatTy">>;
+def Double : Type<"double", QualType<"DoubleTy">>;
+def Half : Type<"half", QualType<"HalfTy">>;
+def Size : Type<"size_t", QualType<"getSizeType()">>;
+def PtrDiff : Type<"ptrdiff_t", QualType<"getPointerDiffType()">>;
+def IntPtr : Type<"intptr_t", QualType<"getIntPtrType()">>;
+def UIntPtr : Type<"uintPtr_t", QualType<"getUIntPtrType()">>;
+def Void : Type<"void_t", QualType<"VoidTy">>;
+
+// OpenCL v1.0/1.2/2.0 s6.1.2: Built-in Vector Data Types.
+// Built-in vector data types are created by TableGen's OpenCLBuiltinEmitter.
+
+// OpenCL v1.0/1.2/2.0 s6.1.3: Other Built-in Data Types.
+// The image definitions are "abstract". They should not be used without
+// specifying an access qualifier (RO/WO/RW).
+def Image1d : Type<"Image1d", QualType<"OCLImage1d", 1>>;
+def Image2d : Type<"Image2d", QualType<"OCLImage2d", 1>>;
+def Image3d : Type<"Image3d", QualType<"OCLImage3d", 1>>;
+def Image1dArray : Type<"Image1dArray", QualType<"OCLImage1dArray", 1>>;
+def Image1dBuffer : Type<"Image1dBuffer", QualType<"OCLImage1dBuffer", 1>>;
+def Image2dArray : Type<"Image2dArray", QualType<"OCLImage2dArray", 1>>;
+def Image2dDepth : Type<"Image2dDepth", QualType<"OCLImage2dDepth", 1>>;
+def Image2dArrayDepth : Type<"Image2dArrayDepth", QualType<"OCLImage2dArrayDepth", 1>>;
+def Image2dMsaa : Type<"Image2dMsaa", QualType<"OCLImage2dMSAA", 1>>;
+def Image2dArrayMsaa : Type<"Image2dArrayMsaa", QualType<"OCLImage2dArrayMSAA", 1>>;
+def Image2dMsaaDepth : Type<"Image2dMsaaDepth", QualType<"OCLImage2dMSAADepth", 1>>;
+def Image2dArrayMsaaDepth : Type<"Image2dArrayMsaaDepth", QualType<"OCLImage2dArrayMSAADepth", 1>>;
+
+def Sampler : Type<"Sampler", QualType<"OCLSamplerTy">>;
+def Event : Type<"Event", QualType<"OCLEventTy">>;
+
//===----------------------------------------------------------------------===//
-// Definitions of OpenCL C types
+// Definitions of OpenCL gentype variants
//===----------------------------------------------------------------------===//
-// OpenCL v1.2 s6.1.1: Built-in Scalar Data Types
-def bool_t : Type<"bool", QualType<"BoolTy">>;
-def char_t : Type<"char", QualType<"CharTy">>;
-def uchar_t : Type<"uchar", QualType<"UnsignedCharTy">>;
-def short_t : Type<"short", QualType<"ShortTy">>;
-def ushort_t : Type<"ushort", QualType<"UnsignedShortTy">>;
-def int_t : Type<"int", QualType<"IntTy">>;
-def uint_t : Type<"uint", QualType<"UnsignedIntTy">>;
-def long_t : Type<"long", QualType<"LongTy">>;
-def ulong_t : Type<"ulong", QualType<"UnsignedLongTy">>;
-def float_t : Type<"float", QualType<"FloatTy">>;
-def double_t : Type<"double", QualType<"DoubleTy">>;
-def half_t : Type<"half", QualType<"HalfTy">>;
-def size_t : Type<"size_t", QualType<"getSizeType()">>;
-def ptrdiff_t : Type<"ptrdiff_t", QualType<"getPointerDiffType()">>;
-def intptr_t : Type<"intptr_t", QualType<"getIntPtrType()">>;
-def uintptr_t : Type<"uintptr_t", QualType<"getUIntPtrType()">>;
-def void_t : Type<"void", QualType<"VoidTy">>;
-
-// OpenCL v1.2 s6.1.2: Built-in Vector Data Types
-foreach v = [2, 3, 4, 8, 16] in {
- def char#v#_t : VectorType<char_t, v>;
- def uchar#v#_t : VectorType<uchar_t, v>;
- def short#v#_t : VectorType<short_t, v>;
- def ushort#v#_t : VectorType<ushort_t, v>;
- def "int"#v#_t : VectorType<int_t, v>;
- def uint#v#_t : VectorType<uint_t, v>;
- def long#v#_t : VectorType<long_t, v>;
- def ulong#v#_t : VectorType<ulong_t, v>;
- def float#v#_t : VectorType<float_t, v>;
- def double#v#_t : VectorType<double_t, v>;
- def half#v#_t : VectorType<half_t, v>;
-}
-
-// OpenCL v1.2 s6.1.3: Other Built-in Data Types
-// These definitions with a "null" name are "abstract". They should not
-// be used in definitions of Builtin functions.
-def image2d_t : Type<"image2d_t", QualType<"null">>;
-def image3d_t : Type<"image3d_t", QualType<"null">>;
-def image2d_array_t : Type<"image2d_array_t", QualType<"null">>;
-def image1d_t : Type<"image1d_t", QualType<"null">>;
-def image1d_buffer_t : Type<"image1d_buffer_t", QualType<"null">>;
-def image1d_array_t : Type<"image1d_array_t", QualType<"null">>;
-// Unlike the few functions above, the following definitions can be used
-// in definitions of Builtin functions (they have a QualType with a name).
-foreach v = ["RO", "WO", "RW"] in {
- def image2d_#v#_t : ImageType<image2d_t,
- QualType<"OCLImage2d"#v#"Ty">,
- v>;
- def image3d_#v#_t : ImageType<image3d_t,
- QualType<"OCLImage3d"#v#"Ty">,
- v>;
- def image2d_array#v#_t : ImageType<image2d_array_t,
- QualType<"OCLImage2dArray"#v#"Ty">,
- v>;
- def image1d_#v#_t : ImageType<image1d_t,
- QualType<"OCLImage1d"#v#"Ty">,
- v>;
- def image1d_buffer#v#_t : ImageType<image1d_buffer_t,
- QualType<"OCLImage1dBuffer"#v#"Ty">,
- v>;
- def image1d_array#v#_t : ImageType<image1d_array_t,
- QualType<"OCLImage1dArray"#v#"Ty">,
- v>;
-}
-
-def sampler_t : Type<"sampler_t", QualType<"OCLSamplerTy">>;
-def event_t : Type<"event_t", QualType<"OCLEventTy">>;
+// The OpenCL specification often uses "gentype" in builtin function
+// declarations to indicate that a builtin function is available with various
+// argument and return types. The types represented by "gentype" vary between
+// different parts of the specification. The following definitions capture
+// the different type lists for gentypes in different parts of the
+// specification.
+
+// Vector width lists.
+def VecAndScalar: IntList<"VecAndScalar", [1, 2, 3, 4, 8, 16]>;
+def VecNoScalar : IntList<"VecNoScalar", [2, 3, 4, 8, 16]>;
+def Vec1 : IntList<"Vec1", [1]>;
+
+// Type lists.
+def TLAll : TypeList<"TLAll", [Char, UChar, Short, UShort, Int, UInt, Long, ULong, Float, Double, Half]>;
+def TLFloat : TypeList<"TLFloat", [Float, Double, Half]>;
+
+def TLAllInts : TypeList<"TLAllInts", [Char, UChar, Short, UShort, Int, UInt, Long, ULong]>;
+
+// GenType definitions for multiple base types (e.g. all floating point types,
+// or all integer types).
+// All types
+def AGenTypeN : GenericType<"AGenTypeN", TLAll, VecAndScalar>;
+def AGenTypeNNoScalar : GenericType<"AGenTypeNNoScalar", TLAll, VecNoScalar>;
+// All integer
+def AIGenType1 : GenericType<"AIGenType1", TLAllInts, Vec1>;
+def AIGenTypeN : GenericType<"AIGenTypeN", TLAllInts, VecAndScalar>;
+def AIGenTypeNNoScalar : GenericType<"AIGenTypeNNoScalar", TLAllInts, VecNoScalar>;
+// Float
+def FGenTypeN : GenericType<"FGenTypeN", TLFloat, VecAndScalar>;
+
+// GenType definitions for every single base type (e.g. fp32 only).
+// Names are like: GenTypeFloatVecAndScalar.
+foreach Type = [Char, UChar, Short, UShort,
+ Int, UInt, Long, ULong,
+ Float, Double, Half] in {
+ foreach VecSizes = [VecAndScalar, VecNoScalar] in {
+ def "GenType" # Type # VecSizes :
+ GenericType<"GenType" # Type # VecSizes,
+ TypeList<"GL" # Type.Name, [Type]>,
+ VecSizes>;
+ }
+}
+
//===----------------------------------------------------------------------===//
// Definitions of OpenCL builtin functions
//===----------------------------------------------------------------------===//
-// OpenCL v1.2 s6.2.3: Explicit Conversions
-// Generate the convert_ builtins.
-foreach RType = [float_t, double_t, char_t, uchar_t, short_t, ushort_t,
- int_t, uint_t, long_t, ulong_t] in {
- foreach IType = [float_t, double_t, char_t, uchar_t, short_t, ushort_t,
- int_t, uint_t, long_t, ulong_t] in {
+//--------------------------------------------------------------------
+// OpenCL v1.1/1.2/2.0 s6.2.3 - Explicit conversions.
+// OpenCL v2.0 Extensions s5.1.1 and s6.1.1 - Conversions.
+
+// Generate the convert_* builtins functions.
+foreach RType = [Float, Double, Half, Char, UChar, Short,
+ UShort, Int, UInt, Long, ULong] in {
+ foreach IType = [Float, Double, Half, Char, UChar, Short,
+ UShort, Int, UInt, Long, ULong] in {
foreach sat = ["", "_sat"] in {
- foreach rte = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
- def : Builtin<"convert_" # RType.Name # sat # rte, [RType, IType]>;
+ foreach rnd = ["", "_rte", "_rtn", "_rtp", "_rtz"] in {
+ def : Builtin<"convert_" # RType.Name # sat # rnd, [RType, IType]>;
foreach v = [2, 3, 4, 8, 16] in {
- def : Builtin<"convert_" # RType.Name # v # sat # rte,
+ def : Builtin<"convert_" # RType.Name # v # sat # rnd,
[VectorType<RType, v>,
VectorType<IType, v>]>;
}
@@ -246,51 +318,357 @@ foreach RType = [float_t, double_t, char_t, uchar_t, short_t, ushort_t,
}
}
-// OpenCL v1.2 s6.12.1: Work-Item Functions
-def get_work_dim : Builtin<"get_work_dim", [uint_t]>;
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.1, v1.2 s6.12.1, v2.0 s6.13.1 - Work-item Functions
+// --- Table 7 ---
+def : Builtin<"get_work_dim", [UInt]>;
foreach name = ["get_global_size", "get_global_id", "get_local_size",
"get_local_id", "get_num_groups", "get_group_id",
"get_global_offset"] in {
- def : Builtin<name, [size_t, uint_t]>;
+ def : Builtin<name, [Size, UInt]>;
+}
+
+let MinVersion = CL20 in {
+ def : Builtin<"get_enqueued_local_size", [Size, UInt]>;
+ foreach name = ["get_global_linear_id", "get_local_linear_id"] in {
+ def : Builtin<name, [Size]>;
+ }
+}
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.7, v1.2 s6.12.7, v2.0 s6.13.7 - Vector Data Load and Store Functions
+// OpenCL Extension v1.1 s9.3.6 and s9.6.6, v1.2 s9.5.6, v2.0 s9.4.6, v2.0 s5.1.6 and 6.1.6 - Vector Data Load and Store Functions
+// --- Table 15 ---
+// Variants for OpenCL versions below 2.0, using pointers to the global, local
+// and private address spaces.
+let MaxVersion = CL20 in {
+ foreach AS = [GlobalAS, LocalAS, PrivateAS] in {
+ foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vload" # VSize] in {
+ def : Builtin<name, [VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, AS>]>;
+ def : Builtin<name, [VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, AS>]>;
+ def : Builtin<name, [VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, AS>]>;
+ def : Builtin<name, [VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, AS>]>;
+ def : Builtin<name, [VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, AS>]>;
+ def : Builtin<name, [VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, AS>]>;
+ def : Builtin<name, [VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, AS>]>;
+ def : Builtin<name, [VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, AS>]>;
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, AS>]>;
+ def : Builtin<name, [VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, AS>]>;
+ def : Builtin<name, [VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
+ }
+ foreach name = ["vstore" # VSize] in {
+ def : Builtin<name, [Void, VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, AS>]>;
+ def : Builtin<name, [Void, VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, AS>]>;
+ def : Builtin<name, [Void, VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, AS>]>;
+ def : Builtin<name, [Void, VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, AS>]>;
+ def : Builtin<name, [Void, VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, AS>]>;
+ def : Builtin<name, [Void, VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, AS>]>;
+ def : Builtin<name, [Void, VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, AS>]>;
+ def : Builtin<name, [Void, VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, AS>]>;
+ def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, AS>]>;
+ def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, AS>]>;
+ def : Builtin<name, [Void, VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
+ }
+ foreach name = ["vloada_half" # VSize] in {
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>;
+ }
+ foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
+ foreach name = ["vstorea_half" # VSize # rnd] in {
+ def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, AS>]>;
+ def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, AS>]>;
+ }
+ }
+ }
+ }
+}
+// Variants for OpenCL versions above 2.0, using pointers to the generic
+// address space.
+let MinVersion = CL20 in {
+ foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vload" # VSize] in {
+ def : Builtin<name, [VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, GenericAS>]>;
+ def : Builtin<name, [VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, GenericAS>]>;
+ def : Builtin<name, [VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, GenericAS>]>;
+ def : Builtin<name, [VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, GenericAS>]>;
+ def : Builtin<name, [VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, GenericAS>]>;
+ def : Builtin<name, [VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, GenericAS>]>;
+ def : Builtin<name, [VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, GenericAS>]>;
+ def : Builtin<name, [VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, GenericAS>]>;
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, GenericAS>]>;
+ def : Builtin<name, [VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, GenericAS>]>;
+ def : Builtin<name, [VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, GenericAS>]>;
+ }
+ foreach name = ["vstore" # VSize] in {
+ def : Builtin<name, [Void, VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, GenericAS>]>;
+ }
+ foreach name = ["vloada_half" # VSize] in {
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, GenericAS>]>;
+ }
+ foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
+ foreach name = ["vstorea_half" # VSize # rnd] in {
+ def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, GenericAS>]>;
+ def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, GenericAS>]>;
+ }
+ }
+ }
+}
+// Variants using pointers to the constant address space.
+foreach VSize = [2, 3, 4, 8, 16] in {
+ foreach name = ["vload" # VSize] in {
+ def : Builtin<name, [VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, ConstantAS>]>;
+ def : Builtin<name, [VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, ConstantAS>]>;
+ }
+ foreach name = ["vloada_half" # VSize] in {
+ def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, ConstantAS>]>;
+ }
+ foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in {
+ foreach name = ["vstorea_half" # VSize # rnd] in {
+ def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, ConstantAS>]>;
+ def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, ConstantAS>]>;
+ }
+ }
+}
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.10, v1.2 s6.12.10, v2.0 s6.13.10: Async Copies from Global to Local Memory, Local to Global Memory, and Prefetch
+// OpenCL Extension v2.0 s5.1.7 and s6.1.7: Async Copies from Global to Local Memory, Local to Global Memory, and Prefetch
+// --- Table 18 ---
+foreach name = ["async_work_group_copy"] in {
+ def : Builtin<name, [Event, PointerType<AGenTypeN, LocalAS>, PointerType<ConstType<AGenTypeN>, GlobalAS>, Size, Event]>;
+ def : Builtin<name, [Event, PointerType<AGenTypeN, GlobalAS>, PointerType<ConstType<AGenTypeN>, LocalAS>, Size, Event]>;
+}
+foreach name = ["async_work_group_strided_copy"] in {
+ def : Builtin<name, [Event, PointerType<AGenTypeN, LocalAS>, PointerType<ConstType<AGenTypeN>, GlobalAS>, Size, Size, Event]>;
+ def : Builtin<name, [Event, PointerType<AGenTypeN, GlobalAS>, PointerType<ConstType<AGenTypeN>, LocalAS>, Size, Size, Event]>;
+}
+foreach name = ["wait_group_events"] in {
+ def : Builtin<name, [Void, Int, PointerType<Event, GenericAS>]>;
+}
+foreach name = ["prefetch"] in {
+ def : Builtin<name, [Void, PointerType<ConstType<AGenTypeN>, GlobalAS>, Size]>;
+}
+
+//--------------------------------------------------------------------
+// OpenCL v2.0 s6.13.11 - Atomics Functions.
+// Functions that use memory_order and cl_mem_fence_flags enums are not
+// declared here as the TableGen backend does not handle enums.
+
+// OpenCL v1.0 s9.5, s9.6, s9.7 - Atomic Functions for 32-bit integers.
+// --- Table 9.1 ---
+foreach Type = [Int, UInt] in {
+ foreach name = ["atom_add", "atom_sub", "atom_xchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type]>;
+ }
+ foreach name = ["atom_inc", "atom_dec"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>]>;
+ }
+ foreach name = ["atom_cmpxchg"] in {
+ def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type, Type]>;
+ }
}
// OpenCL v1.2 s6.12.2: Math Functions
foreach name = ["acos", "acosh", "acospi",
"asin", "asinh", "asinpi",
"atan", "atanh", "atanpi"] in {
- foreach type = [float_t, double_t, half_t] in {
- defm : Bif1<name, [type, type], [1, 1]>;
- }
+ def : Builtin<name, [FGenTypeN, FGenTypeN]>;
}
foreach name = ["atan2", "atan2pi"] in {
- foreach type = [float_t, double_t, half_t] in {
- defm : Bif2<name, [type, type, type], [1, 1, 1]>;
- }
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN]>;
}
foreach name = ["fmax", "fmin"] in {
- foreach type = [float_t, double_t, half_t] in {
- defm : Bif2<name, [type, type, type], [1, 1, 1]>;
- defm : Bif2<name, [type, type, type], [1, 1, 0]>;
+ def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN]>;
+ def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Float]>;
+ def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Double]>;
+ def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Half]>;
+}
+
+// OpenCL v1.1 s6.11.3, v1.2 s6.12.3, v2.0 s6.13.3 - Integer Functions
+foreach name = ["max", "min"] in {
+ def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN]>;
+ def : Builtin<name, [AIGenTypeNNoScalar, AIGenTypeNNoScalar, AIGenType1]>;
+}
+
+//--------------------------------------------------------------------
+// OpenCL v1.1 s6.11.3, v1.2 s6.12.14, v2.0 s6.13.14: Image Read and Write Functions
+// OpenCL Extension v2.0 s5.1.8 and s6.1.8: Image Read and Write Functions
+// --- Table 22: Image Read Functions with Samplers ---
+foreach imgTy = [Image1d] in {
+ foreach coordTy = [Int, Float] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>;
+ }
+}
+foreach imgTy = [Image2d, Image1dArray] in {
+ foreach coordTy = [Int, Float] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>;
}
}
+foreach imgTy = [Image3d, Image2dArray] in {
+ foreach coordTy = [Int, Float] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>;
+ }
+}
+foreach coordTy = [Int, Float] in {
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, "RO">, Sampler, VectorType<coordTy, 2>]>;
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, "RO">, Sampler, VectorType<coordTy, 4>]>;
+}
-// OpenCL v1.2 s6.12.14: Built-in Image Read Functions
-def read_imagef : Builtin<"read_imagef",
- [float4_t, image2d_RO_t, VectorType<int_t, 2>]>;
-def write_imagef : Builtin<"write_imagef",
- [void_t,
- image2d_WO_t,
- VectorType<int_t, 2>,
- VectorType<float_t, 4>]>;
+// --- Table 23: Sampler-less Read Functions ---
+foreach aQual = ["RO", "RW"] in {
+ foreach imgTy = [Image2d, Image1dArray] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+ }
+ foreach imgTy = [Image3d, Image2dArray] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+ }
+ foreach imgTy = [Image1d, Image1dBuffer] in {
+ def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, Int]>;
+ def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, Int]>;
+ def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Int]>;
+ }
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>]>;
+ def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>]>;
+}
+
+// --- Table 24: Image Write Functions ---
+foreach aQual = ["WO", "RW"] in {
+ foreach imgTy = [Image2d] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<UInt, 4>]>;
+ }
+ foreach imgTy = [Image2dArray] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<UInt, 4>]>;
+ }
+ foreach imgTy = [Image1d, Image1dBuffer] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, Int, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, Int, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, Int, VectorType<UInt, 4>]>;
+ }
+ foreach imgTy = [Image1dArray] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, VectorType<UInt, 4>]>;
+ }
+ foreach imgTy = [Image3d] in {
+ def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Float, 4>]>;
+ def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<Int, 4>]>;
+ def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, VectorType<UInt, 4>]>;
+ }
+ def : Builtin<"write_imagef", [Void, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>, Float]>;
+ def : Builtin<"write_imagef", [Void, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>, Float]>;
+}
+
+// --- Table 25: Image Query Functions ---
+foreach aQual = ["RO", "WO", "RW"] in {
+ foreach imgTy = [Image1d, Image1dBuffer, Image2d, Image3d,
+ Image1dArray, Image2dArray, Image2dDepth,
+ Image2dArrayDepth] in {
+ foreach name = ["get_image_width", "get_image_channel_data_type",
+ "get_image_channel_order"] in {
+ def : Builtin<name, [Int, ImageType<imgTy, aQual>]>;
+ }
+ }
+ foreach imgTy = [Image2d, Image3d, Image2dArray, Image2dDepth,
+ Image2dArrayDepth] in {
+ def : Builtin<"get_image_height", [Int, ImageType<imgTy, aQual>]>;
+ }
+ def : Builtin<"get_image_depth", [Int, ImageType<Image3d, aQual>]>;
+ foreach imgTy = [Image2d, Image2dArray, Image2dDepth,
+ Image2dArrayDepth] in {
+ def : Builtin<"get_image_dim", [VectorType<Int, 2>, ImageType<imgTy, aQual>]>;
+ }
+ def : Builtin<"get_image_dim", [VectorType<Int, 4>, ImageType<Image3d, aQual>]>;
+ foreach imgTy = [Image1dArray, Image2dArray, Image2dArrayDepth] in {
+ def : Builtin<"get_image_array_size", [Size, ImageType<imgTy, aQual>]>;
+ }
+}
+
+// OpenCL extension v2.0 s5.1.9: Built-in Image Read Functions
+// --- Table 8 ---
+foreach aQual = ["RO"] in {
+ foreach name = ["read_imageh"] in {
+ foreach coordTy = [Int, Float] in {
+ foreach imgTy = [Image2d, Image1dArray] in {
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 2>]>;
+ }
+ foreach imgTy = [Image3d, Image2dArray] in {
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 4>]>;
+ }
+ foreach imgTy = [Image1d] in {
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, coordTy]>;
+ }
+ }
+ }
+}
+// OpenCL extension v2.0 s5.1.10: Built-in Image Sampler-less Read Functions
+// --- Table 9 ---
+foreach aQual = ["RO", "RW"] in {
+ foreach name = ["read_imageh"] in {
+ foreach imgTy = [Image2d, Image1dArray] in {
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>;
+ }
+ foreach imgTy = [Image3d, Image2dArray] in {
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>;
+ }
+ foreach imgTy = [Image1d, Image1dBuffer] in {
+ def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Int]>;
+ }
+ }
+}
+// OpenCL extension v2.0 s5.1.11: Built-in Image Write Functions
+// --- Table 10 ---
+foreach aQual = ["WO", "RW"] in {
+ foreach name = ["write_imageh"] in {
+ def : Builtin<name, [Void, ImageType<Image2d, aQual>, VectorType<Int, 2>, VectorType<Half, 4>]>;
+ def : Builtin<name, [Void, ImageType<Image2dArray, aQual>, VectorType<Int, 4>, VectorType<Half, 4>]>;
+ def : Builtin<name, [Void, ImageType<Image1d, aQual>, Int, VectorType<Half, 4>]>;
+ def : Builtin<name, [Void, ImageType<Image1dBuffer, aQual>, Int, VectorType<Half, 4>]>;
+ def : Builtin<name, [Void, ImageType<Image1dArray, aQual>, VectorType<Int, 2>, VectorType<Half, 4>]>;
+ def : Builtin<name, [Void, ImageType<Image3d, aQual>, VectorType<Int, 4>, VectorType<Half, 4>]>;
+ }
+}
// OpenCL v2.0 s9.17.3: Additions to section 6.13.1: Work-Item Functions
-let Version = CL20 in {
+let MinVersion = CL20 in {
let Extension = "cl_khr_subgroups" in {
- def get_sub_group_size : Builtin<"get_sub_group_size", [uint_t]>;
- def get_max_sub_group_size : Builtin<"get_max_sub_group_size", [uint_t]>;
- def get_num_sub_groups : Builtin<"get_num_sub_groups", [uint_t]>;
+ def get_sub_group_size : Builtin<"get_sub_group_size", [UInt]>;
+ def get_max_sub_group_size : Builtin<"get_max_sub_group_size", [UInt]>;
+ def get_num_sub_groups : Builtin<"get_num_sub_groups", [UInt]>;
}
}
diff --git a/lib/Sema/ParsedAttr.cpp b/lib/Sema/ParsedAttr.cpp
index 5c04443460bc..5d0a734f237a 100644
--- a/lib/Sema/ParsedAttr.cpp
+++ b/lib/Sema/ParsedAttr.cpp
@@ -100,71 +100,6 @@ void AttributePool::takePool(AttributePool &pool) {
pool.Attrs.clear();
}
-#include "clang/Sema/AttrParsedAttrKinds.inc"
-
-static StringRef normalizeAttrScopeName(StringRef ScopeName,
- ParsedAttr::Syntax SyntaxUsed) {
- // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name
- // to be "clang".
- if (SyntaxUsed == ParsedAttr::AS_CXX11 ||
- SyntaxUsed == ParsedAttr::AS_C2x) {
- if (ScopeName == "__gnu__")
- ScopeName = "gnu";
- else if (ScopeName == "_Clang")
- ScopeName = "clang";
- }
- return ScopeName;
-}
-
-static StringRef normalizeAttrName(StringRef AttrName,
- StringRef NormalizedScopeName,
- ParsedAttr::Syntax SyntaxUsed) {
- // Normalize the attribute name, __foo__ becomes foo. This is only allowable
- // for GNU attributes, and attributes using the double square bracket syntax.
- bool ShouldNormalize =
- SyntaxUsed == ParsedAttr::AS_GNU ||
- ((SyntaxUsed == ParsedAttr::AS_CXX11 ||
- SyntaxUsed == ParsedAttr::AS_C2x) &&
- (NormalizedScopeName == "gnu" || NormalizedScopeName == "clang"));
- if (ShouldNormalize && AttrName.size() >= 4 && AttrName.startswith("__") &&
- AttrName.endswith("__"))
- AttrName = AttrName.slice(2, AttrName.size() - 2);
-
- return AttrName;
-}
-
-ParsedAttr::Kind ParsedAttr::getKind(const IdentifierInfo *Name,
- const IdentifierInfo *ScopeName,
- Syntax SyntaxUsed) {
- StringRef AttrName = Name->getName();
-
- SmallString<64> FullName;
- if (ScopeName)
- FullName += normalizeAttrScopeName(ScopeName->getName(), SyntaxUsed);
-
- AttrName = normalizeAttrName(AttrName, FullName, SyntaxUsed);
-
- // Ensure that in the case of C++11 attributes, we look for '::foo' if it is
- // unscoped.
- if (ScopeName || SyntaxUsed == AS_CXX11 || SyntaxUsed == AS_C2x)
- FullName += "::";
- FullName += AttrName;
-
- return ::getAttrKind(FullName, SyntaxUsed);
-}
-
-unsigned ParsedAttr::getAttributeSpellingListIndex() const {
- // Both variables will be used in tablegen generated
- // attribute spell list index matching code.
- auto Syntax = static_cast<ParsedAttr::Syntax>(SyntaxUsed);
- StringRef Scope =
- ScopeName ? normalizeAttrScopeName(ScopeName->getName(), Syntax) : "";
- StringRef Name = normalizeAttrName(AttrName->getName(), Scope, Syntax);
-
-#include "clang/Sema/AttrSpellingListIndex.inc"
-
-}
-
struct ParsedAttrInfo {
unsigned NumArgs : 4;
unsigned OptArgs : 4;
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 11fed28b52db..bedea2167950 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/Stack.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
@@ -37,6 +38,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TemplateInstCallback.h"
+#include "clang/Sema/TypoCorrection.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/TimeProfiler.h"
@@ -181,7 +183,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
InitDataSharingAttributesStack();
std::unique_ptr<sema::SemaPPCallbacks> Callbacks =
- llvm::make_unique<sema::SemaPPCallbacks>();
+ std::make_unique<sema::SemaPPCallbacks>();
SemaPPCallbackHandler = Callbacks.get();
PP.addPPCallbacks(std::move(Callbacks));
SemaPPCallbackHandler->set(*this);
@@ -335,7 +337,13 @@ void Sema::Initialize() {
addImplicitTypedef(#ExtType, Context.Id##Ty); \
setOpenCLExtensionForType(Context.Id##Ty, #Ext);
#include "clang/Basic/OpenCLExtensionTypes.def"
- };
+ }
+
+ if (Context.getTargetInfo().hasAArch64SVETypes()) {
+#define SVE_TYPE(Name, Id, SingletonId) \
+ addImplicitTypedef(Name, Context.SingletonId);
+#include "clang/Basic/AArch64SVEACLETypes.def"
+ }
if (Context.getTargetInfo().hasBuiltinMSVaList()) {
DeclarationName MSVaList = &Context.Idents.get("__builtin_ms_va_list");
@@ -376,8 +384,19 @@ Sema::~Sema() {
// Detach from the PP callback handler which outlives Sema since it's owned
// by the preprocessor.
SemaPPCallbackHandler->reset();
+}
+
+void Sema::warnStackExhausted(SourceLocation Loc) {
+ // Only warn about this once.
+ if (!WarnedStackExhausted) {
+ Diag(Loc, diag::warn_stack_exhausted);
+ WarnedStackExhausted = true;
+ }
+}
- assert(DelayedTypos.empty() && "Uncorrected typos!");
+void Sema::runWithSufficientStackSpace(SourceLocation Loc,
+ llvm::function_ref<void()> Fn) {
+ clang::runWithSufficientStackSpace([&] { warnStackExhausted(Loc); }, Fn);
}
/// makeUnavailableInSystemHeader - There is an error in the current
@@ -907,9 +926,22 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) {
PerformPendingInstantiations();
}
+ // Finalize analysis of OpenMP-specific constructs.
+ if (LangOpts.OpenMP)
+ finalizeOpenMPDelayedAnalysis();
+
assert(LateParsedInstantiations.empty() &&
"end of TU template instantiation should not create more "
"late-parsed templates");
+
+ // Report diagnostics for uncorrected delayed typos. Ideally all of them
+ // should have been corrected by that time, but it is very hard to cover all
+ // cases in practice.
+ for (const auto &Typo : DelayedTypos) {
+ // We pass an empty TypoCorrection to indicate no correction was performed.
+ Typo.second.DiagHandler(TypoCorrection());
+ }
+ DelayedTypos.clear();
}
/// ActOnEndOfTranslationUnit - This is called at the very end of the
@@ -961,6 +993,7 @@ void Sema::ActOnEndOfTranslationUnit() {
// All dllexport classes should have been processed already.
assert(DelayedDllExportClasses.empty());
+ assert(DelayedDllExportMemberFunctions.empty());
// Remove file scoped decls that turned out to be used.
UnusedFileScopedDecls.erase(
@@ -1086,8 +1119,8 @@ void Sema::ActOnEndOfTranslationUnit() {
// Set the length of the array to 1 (C99 6.9.2p5).
Diag(VD->getLocation(), diag::warn_tentative_incomplete_array);
llvm::APInt One(Context.getTypeSize(Context.getSizeType()), true);
- QualType T = Context.getConstantArrayType(ArrayT->getElementType(),
- One, ArrayType::Normal, 0);
+ QualType T = Context.getConstantArrayType(ArrayT->getElementType(), One,
+ nullptr, ArrayType::Normal, 0);
VD->setType(T);
} else if (RequireCompleteType(VD->getLocation(), VD->getType(),
diag::err_tentative_def_incomplete_type))
@@ -1282,7 +1315,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
}
- Diags.setLastDiagnosticIgnored();
+ Diags.setLastDiagnosticIgnored(true);
Diags.Clear();
return;
@@ -1307,7 +1340,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
PartialDiagnostic(DiagInfo, Context.getDiagAllocator()));
}
- Diags.setLastDiagnosticIgnored();
+ Diags.setLastDiagnosticIgnored(true);
Diags.Clear();
// Now the diagnostic state is clear, produce a C++98 compatibility
@@ -1316,7 +1349,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
// The last diagnostic which Sema produced was ignored. Suppress any
// notes attached to it.
- Diags.setLastDiagnosticIgnored();
+ Diags.setLastDiagnosticIgnored(true);
return;
}
@@ -1330,7 +1363,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
}
// Suppress this diagnostic.
- Diags.setLastDiagnosticIgnored();
+ Diags.setLastDiagnosticIgnored(true);
Diags.Clear();
return;
}
@@ -1376,7 +1409,7 @@ static void emitCallStackNotes(Sema &S, FunctionDecl *FD) {
// Emit any deferred diagnostics for FD and erase them from the map in which
// they're stored.
-static void emitDeferredDiags(Sema &S, FunctionDecl *FD) {
+static void emitDeferredDiags(Sema &S, FunctionDecl *FD, bool ShowCallStack) {
auto It = S.DeviceDeferredDiags.find(FD);
if (It == S.DeviceDeferredDiags.end())
return;
@@ -1395,7 +1428,7 @@ static void emitDeferredDiags(Sema &S, FunctionDecl *FD) {
// FIXME: Should this be called after every warning/error emitted in the loop
// above, instead of just once per function? That would be consistent with
// how we handle immediate errors, but it also seems like a bit much.
- if (HasWarningOrError)
+ if (HasWarningOrError && ShowCallStack)
emitCallStackNotes(S, FD);
}
@@ -1498,7 +1531,7 @@ void Sema::markKnownEmitted(
assert(!IsKnownEmitted(S, C.Callee) &&
"Worklist should not contain known-emitted functions.");
S.DeviceKnownEmittedFns[C.Callee] = {C.Caller, C.Loc};
- emitDeferredDiags(S, C.Callee);
+ emitDeferredDiags(S, C.Callee, C.Caller);
// If this is a template instantiation, explore its callgraph as well:
// Non-dependent calls are part of the template's callgraph, while dependent
@@ -1535,8 +1568,9 @@ void Sema::markKnownEmitted(
}
Sema::DeviceDiagBuilder Sema::targetDiag(SourceLocation Loc, unsigned DiagID) {
- if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)
- return diagIfOpenMPDeviceCode(Loc, DiagID);
+ if (LangOpts.OpenMP)
+ return LangOpts.OpenMPIsDevice ? diagIfOpenMPDeviceCode(Loc, DiagID)
+ : diagIfOpenMPHostCode(Loc, DiagID);
if (getLangOpts().CUDA)
return getLangOpts().CUDAIsDevice ? CUDADiagIfDeviceCode(Loc, DiagID)
: CUDADiagIfHostCode(Loc, DiagID);
@@ -1790,6 +1824,22 @@ FunctionScopeInfo *Sema::getEnclosingFunction() const {
return nullptr;
}
+LambdaScopeInfo *Sema::getEnclosingLambda() const {
+ for (auto *Scope : llvm::reverse(FunctionScopes)) {
+ if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Scope)) {
+ if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext)) {
+ // We have switched contexts due to template instantiation.
+ // FIXME: We should swap out the FunctionScopes during code synthesis
+ // so that we don't need to check for this.
+ assert(!CodeSynthesisContexts.empty());
+ return nullptr;
+ }
+ return LSI;
+ }
+ }
+ return nullptr;
+}
+
LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) {
if (FunctionScopes.empty())
return nullptr;
@@ -1812,6 +1862,7 @@ LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) {
return CurLSI;
}
+
// We have a generic lambda if we parsed auto parameters, or we have
// an associated template parameter list.
LambdaScopeInfo *Sema::getCurGenericLambda() {
@@ -1934,11 +1985,9 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy,
// member templates with defaults/deduction of template arguments, overloads
// with default arguments, etc.
if (IsMemExpr && !E.isTypeDependent()) {
- bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
- getDiagnostics().setSuppressAllDiagnostics(true);
+ Sema::TentativeAnalysisScope Trap(*this);
ExprResult R = BuildCallToMemberFunction(nullptr, &E, SourceLocation(),
None, SourceLocation());
- getDiagnostics().setSuppressAllDiagnostics(Suppress);
if (R.isUsable()) {
ZeroArgCallReturnTy = R.get()->getType();
return true;
@@ -2112,10 +2161,12 @@ IdentifierInfo *Sema::getFloat128Identifier() const {
}
void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD,
- CapturedRegionKind K) {
- CapturingScopeInfo *CSI = new CapturedRegionScopeInfo(
+ CapturedRegionKind K,
+ unsigned OpenMPCaptureLevel) {
+ auto *CSI = new CapturedRegionScopeInfo(
getDiagnostics(), S, CD, RD, CD->getContextParam(), K,
- (getLangOpts().OpenMP && K == CR_OpenMP) ? getOpenMPNestingLevel() : 0);
+ (getLangOpts().OpenMP && K == CR_OpenMP) ? getOpenMPNestingLevel() : 0,
+ OpenMPCaptureLevel);
CSI->ReturnType = Context.VoidTy;
FunctionScopes.push_back(CSI);
}
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index b6fbbbff91f5..9dbb93322b7d 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -1551,7 +1551,7 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
QualType BaseType = E->getBaseType();
if (E->isArrow())
- BaseType = BaseType->getAs<PointerType>()->getPointeeType();
+ BaseType = BaseType->castAs<PointerType>()->getPointeeType();
AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(),
Found, BaseType);
@@ -1834,8 +1834,8 @@ Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
return AR_accessible;
CXXRecordDecl *BaseD, *DerivedD;
- BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
- DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
+ BaseD = cast<CXXRecordDecl>(Base->castAs<RecordType>()->getDecl());
+ DerivedD = cast<CXXRecordDecl>(Derived->castAs<RecordType>()->getDecl());
AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD,
Path.Access);
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 8e9318847373..70186c966f8f 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -85,6 +85,123 @@ void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
MSVtorDispAttr::CreateImplicit(Context, VtorDispStack.CurrentValue));
}
+template <typename Attribute>
+static void addGslOwnerPointerAttributeIfNotExisting(ASTContext &Context,
+ CXXRecordDecl *Record) {
+ if (Record->hasAttr<OwnerAttr>() || Record->hasAttr<PointerAttr>())
+ return;
+
+ for (Decl *Redecl : Record->redecls())
+ Redecl->addAttr(Attribute::CreateImplicit(Context, /*DerefType=*/nullptr));
+}
+
+void Sema::inferGslPointerAttribute(NamedDecl *ND,
+ CXXRecordDecl *UnderlyingRecord) {
+ if (!UnderlyingRecord)
+ return;
+
+ const auto *Parent = dyn_cast<CXXRecordDecl>(ND->getDeclContext());
+ if (!Parent)
+ return;
+
+ static llvm::StringSet<> Containers{
+ "array",
+ "basic_string",
+ "deque",
+ "forward_list",
+ "vector",
+ "list",
+ "map",
+ "multiset",
+ "multimap",
+ "priority_queue",
+ "queue",
+ "set",
+ "stack",
+ "unordered_set",
+ "unordered_map",
+ "unordered_multiset",
+ "unordered_multimap",
+ };
+
+ static llvm::StringSet<> Iterators{"iterator", "const_iterator",
+ "reverse_iterator",
+ "const_reverse_iterator"};
+
+ if (Parent->isInStdNamespace() && Iterators.count(ND->getName()) &&
+ Containers.count(Parent->getName()))
+ addGslOwnerPointerAttributeIfNotExisting<PointerAttr>(Context,
+ UnderlyingRecord);
+}
+
+void Sema::inferGslPointerAttribute(TypedefNameDecl *TD) {
+
+ QualType Canonical = TD->getUnderlyingType().getCanonicalType();
+
+ CXXRecordDecl *RD = Canonical->getAsCXXRecordDecl();
+ if (!RD) {
+ if (auto *TST =
+ dyn_cast<TemplateSpecializationType>(Canonical.getTypePtr())) {
+
+ RD = dyn_cast_or_null<CXXRecordDecl>(
+ TST->getTemplateName().getAsTemplateDecl()->getTemplatedDecl());
+ }
+ }
+
+ inferGslPointerAttribute(TD, RD);
+}
+
+void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
+ static llvm::StringSet<> StdOwners{
+ "any",
+ "array",
+ "basic_regex",
+ "basic_string",
+ "deque",
+ "forward_list",
+ "vector",
+ "list",
+ "map",
+ "multiset",
+ "multimap",
+ "optional",
+ "priority_queue",
+ "queue",
+ "set",
+ "stack",
+ "unique_ptr",
+ "unordered_set",
+ "unordered_map",
+ "unordered_multiset",
+ "unordered_multimap",
+ "variant",
+ };
+ static llvm::StringSet<> StdPointers{
+ "basic_string_view",
+ "reference_wrapper",
+ "regex_iterator",
+ };
+
+ if (!Record->getIdentifier())
+ return;
+
+ // Handle classes that directly appear in std namespace.
+ if (Record->isInStdNamespace()) {
+ if (Record->hasAttr<OwnerAttr>() || Record->hasAttr<PointerAttr>())
+ return;
+
+ if (StdOwners.count(Record->getName()))
+ addGslOwnerPointerAttributeIfNotExisting<OwnerAttr>(Context, Record);
+ else if (StdPointers.count(Record->getName()))
+ addGslOwnerPointerAttributeIfNotExisting<PointerAttr>(Context, Record);
+
+ return;
+ }
+
+ // Handle nested classes that could be a gsl::Pointer.
+ inferGslPointerAttribute(Record, Record);
+}
+
void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
SourceLocation PragmaLoc) {
PragmaMsStackAction Action = Sema::PSK_Reset;
@@ -149,6 +266,9 @@ void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionA
case PragmaClangSectionKind::PCSK_Rodata:
CSec = &PragmaClangRodataSection;
break;
+ case PragmaClangSectionKind::PCSK_Relro:
+ CSec = &PragmaClangRelroSection;
+ break;
case PragmaClangSectionKind::PCSK_Text:
CSec = &PragmaClangTextSection;
break;
@@ -454,12 +574,15 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
if (VD->isUsed())
Diag(PragmaLoc, diag::warn_used_but_marked_unused) << Name;
- VD->addAttr(UnusedAttr::CreateImplicit(Context, UnusedAttr::GNU_unused,
- IdTok.getLocation()));
+ VD->addAttr(UnusedAttr::CreateImplicit(Context, IdTok.getLocation(),
+ AttributeCommonInfo::AS_Pragma,
+ UnusedAttr::GNU_unused));
}
void Sema::AddCFAuditedAttribute(Decl *D) {
- SourceLocation Loc = PP.getPragmaARCCFCodeAuditedLoc();
+ IdentifierInfo *Ident;
+ SourceLocation Loc;
+ std::tie(Ident, Loc) = PP.getPragmaARCCFCodeAuditedInfo();
if (!Loc.isValid()) return;
// Don't add a redundant or conflicting attribute.
@@ -467,7 +590,9 @@ void Sema::AddCFAuditedAttribute(Decl *D) {
D->hasAttr<CFUnknownTransferAttr>())
return;
- D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Loc));
+ AttributeCommonInfo Info(Ident, SourceRange(Loc),
+ AttributeCommonInfo::AS_Pragma);
+ D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Info));
}
namespace {
@@ -618,7 +743,7 @@ void Sema::ActOnPragmaAttributeAttribute(
if (!Rules.empty()) {
auto Diagnostic =
Diag(PragmaLoc, diag::err_pragma_attribute_invalid_matchers)
- << Attribute.getName();
+ << Attribute;
SmallVector<attr::SubjectMatchRule, 2> ExtraRules;
for (const auto &Rule : Rules) {
ExtraRules.push_back(attr::SubjectMatchRule(Rule.first));
diff --git a/lib/Sema/SemaCUDA.cpp b/lib/Sema/SemaCUDA.cpp
index 203c09c57112..d0ddfd040c9c 100644
--- a/lib/Sema/SemaCUDA.cpp
+++ b/lib/Sema/SemaCUDA.cpp
@@ -267,6 +267,18 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
CXXMethodDecl *MemberDecl,
bool ConstRHS,
bool Diagnose) {
+ // If the defaulted special member is defined lexically outside of its
+ // owning class, or the special member already has explicit device or host
+ // attributes, do not infer.
+ bool InClass = MemberDecl->getLexicalParent() == MemberDecl->getParent();
+ bool HasH = MemberDecl->hasAttr<CUDAHostAttr>();
+ bool HasD = MemberDecl->hasAttr<CUDADeviceAttr>();
+ bool HasExplicitAttr =
+ (HasD && !MemberDecl->getAttr<CUDADeviceAttr>()->isImplicit()) ||
+ (HasH && !MemberDecl->getAttr<CUDAHostAttr>()->isImplicit());
+ if (!InClass || HasExplicitAttr)
+ return false;
+
llvm::Optional<CUDAFunctionTarget> InferredTarget;
// We're going to invoke special member lookup; mark that these special
@@ -371,21 +383,23 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
}
}
+
+ // If no target was inferred, mark this member as __host__ __device__;
+ // it's the least restrictive option that can be invoked from any target.
+ bool NeedsH = true, NeedsD = true;
if (InferredTarget.hasValue()) {
- if (InferredTarget.getValue() == CFT_Device) {
- MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
- } else if (InferredTarget.getValue() == CFT_Host) {
- MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
- } else {
- MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
- MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
- }
- } else {
- // If no target was inferred, mark this member as __host__ __device__;
- // it's the least restrictive option that can be invoked from any target.
+ if (InferredTarget.getValue() == CFT_Device)
+ NeedsH = false;
+ else if (InferredTarget.getValue() == CFT_Host)
+ NeedsD = false;
+ }
+
+ // We either setting attributes first time, or the inferred ones must match
+ // previously set ones.
+ if (NeedsD && !HasD)
MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context));
+ if (NeedsH && !HasH)
MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context));
- }
return false;
}
@@ -586,40 +600,6 @@ void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD,
NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context));
}
-// Do we know that we will eventually codegen the given function?
-static bool IsKnownEmitted(Sema &S, FunctionDecl *FD) {
- // Templates are emitted when they're instantiated.
- if (FD->isDependentContext())
- return false;
-
- // When compiling for device, host functions are never emitted. Similarly,
- // when compiling for host, device and global functions are never emitted.
- // (Technically, we do emit a host-side stub for global functions, but this
- // doesn't count for our purposes here.)
- Sema::CUDAFunctionTarget T = S.IdentifyCUDATarget(FD);
- if (S.getLangOpts().CUDAIsDevice && T == Sema::CFT_Host)
- return false;
- if (!S.getLangOpts().CUDAIsDevice &&
- (T == Sema::CFT_Device || T == Sema::CFT_Global))
- return false;
-
- // Check whether this function is externally visible -- if so, it's
- // known-emitted.
- //
- // We have to check the GVA linkage of the function's *definition* -- if we
- // only have a declaration, we don't know whether or not the function will be
- // emitted, because (say) the definition could include "inline".
- FunctionDecl *Def = FD->getDefinition();
-
- if (Def &&
- !isDiscardableGVALinkage(S.getASTContext().GetGVALinkageForFunction(Def)))
- return true;
-
- // Otherwise, the function is known-emitted if it's in our set of
- // known-emitted functions.
- return S.DeviceKnownEmittedFns.count(FD) > 0;
-}
-
Sema::DeviceDiagBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc,
unsigned DiagID) {
assert(getLangOpts().CUDA && "Should only be called during CUDA compilation");
@@ -633,7 +613,8 @@ Sema::DeviceDiagBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc,
// device code if we're compiling for device. Defer any errors in device
// mode until the function is known-emitted.
if (getLangOpts().CUDAIsDevice) {
- return IsKnownEmitted(*this, dyn_cast<FunctionDecl>(CurContext))
+ return (getEmissionStatus(cast<FunctionDecl>(CurContext)) ==
+ FunctionEmissionStatus::Emitted)
? DeviceDiagBuilder::K_ImmediateWithCallStack
: DeviceDiagBuilder::K_Deferred;
}
@@ -661,7 +642,8 @@ Sema::DeviceDiagBuilder Sema::CUDADiagIfHostCode(SourceLocation Loc,
if (getLangOpts().CUDAIsDevice)
return DeviceDiagBuilder::K_Nop;
- return IsKnownEmitted(*this, dyn_cast<FunctionDecl>(CurContext))
+ return (getEmissionStatus(cast<FunctionDecl>(CurContext)) ==
+ FunctionEmissionStatus::Emitted)
? DeviceDiagBuilder::K_ImmediateWithCallStack
: DeviceDiagBuilder::K_Deferred;
default:
@@ -688,12 +670,16 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) {
// If the caller is known-emitted, mark the callee as known-emitted.
// Otherwise, mark the call in our call graph so we can traverse it later.
- bool CallerKnownEmitted = IsKnownEmitted(*this, Caller);
+ bool CallerKnownEmitted =
+ getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted;
if (CallerKnownEmitted) {
// Host-side references to a __global__ function refer to the stub, so the
// function itself is never emitted and therefore should not be marked.
- if (getLangOpts().CUDAIsDevice || IdentifyCUDATarget(Callee) != CFT_Global)
- markKnownEmitted(*this, Caller, Callee, Loc, IsKnownEmitted);
+ if (!shouldIgnoreInHostDeviceCheck(Callee))
+ markKnownEmitted(
+ *this, Caller, Callee, Loc, [](Sema &S, FunctionDecl *FD) {
+ return S.getEmissionStatus(FD) == FunctionEmissionStatus::Emitted;
+ });
} else {
// If we have
// host fn calls kernel fn calls host+device,
@@ -701,7 +687,7 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) {
// omitting at the call to the kernel from the callgraph. This ensures
// that, when compiling for host, only HD functions actually called from the
// host get marked as known-emitted.
- if (getLangOpts().CUDAIsDevice || IdentifyCUDATarget(Callee) != CFT_Global)
+ if (!shouldIgnoreInHostDeviceCheck(Callee))
DeviceCallGraph[Caller].insert({Callee, Loc});
}
@@ -806,7 +792,8 @@ void Sema::inheritCUDATargetAttrs(FunctionDecl *FD,
std::string Sema::getCudaConfigureFuncName() const {
if (getLangOpts().HIP)
- return "hipConfigureCall";
+ return getLangOpts().HIPUseNewLaunchAPI ? "__hipPushCallConfiguration"
+ : "hipConfigureCall";
// New CUDA kernel launch sequence.
if (CudaFeatureEnabled(Context.getTargetInfo().getSDKVersion(),
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index c473856f0b07..a4421d2b68af 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -440,7 +440,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<NestedNameSpecifierValidatorCCC>(*this);
+ return std::make_unique<NestedNameSpecifierValidatorCCC>(*this);
}
private:
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index f184eda2f273..0ebb5c68f7c2 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -1304,6 +1304,7 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
bool DerivedToBase;
bool ObjCConversion;
bool ObjCLifetimeConversion;
+ bool FunctionConversion;
QualType FromType = SrcExpr->getType();
QualType ToType = R->getPointeeType();
if (CStyle) {
@@ -1313,7 +1314,7 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
Sema::ReferenceCompareResult RefResult = Self.CompareReferenceRelationship(
SrcExpr->getBeginLoc(), ToType, FromType, DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion);
+ ObjCLifetimeConversion, FunctionConversion);
if (RefResult != Sema::Ref_Compatible) {
if (CStyle || RefResult == Sema::Ref_Incompatible)
return TC_NotApplicable;
@@ -2799,6 +2800,15 @@ void CastOperation::CheckCStyleCast() {
void CastOperation::CheckBuiltinBitCast() {
QualType SrcType = SrcExpr.get()->getType();
+
+ if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
+ diag::err_typecheck_cast_to_incomplete) ||
+ Self.RequireCompleteType(OpRange.getBegin(), SrcType,
+ diag::err_incomplete_type)) {
+ SrcExpr = ExprError();
+ return;
+ }
+
if (SrcExpr.get()->isRValue())
SrcExpr = Self.CreateMaterializeTemporaryExpr(SrcType, SrcExpr.get(),
/*IsLValueReference=*/false);
@@ -2826,11 +2836,6 @@ void CastOperation::CheckBuiltinBitCast() {
return;
}
- if (Self.Context.hasSameUnqualifiedType(DestType, SrcType)) {
- Kind = CK_NoOp;
- return;
- }
-
Kind = CK_LValueToRValueBitCast;
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index f9f82cdeef43..dca81d1d275f 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -191,7 +191,7 @@ static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) {
return false;
}
-/// Check the number of arguments, and set the result type to
+/// Check the number of arguments and set the result type to
/// the argument type.
static bool SemaBuiltinPreserveAI(Sema &S, CallExpr *TheCall) {
if (checkArgCount(S, TheCall, 1))
@@ -484,7 +484,7 @@ static bool checkOpenCLBlockArgs(Sema &S, Expr *BlockArg) {
const BlockPointerType *BPT =
cast<BlockPointerType>(BlockArg->getType().getCanonicalType());
ArrayRef<QualType> Params =
- BPT->getPointeeType()->getAs<FunctionProtoType>()->getParamTypes();
+ BPT->getPointeeType()->castAs<FunctionProtoType>()->getParamTypes();
unsigned ArgCounter = 0;
bool IllegalParams = false;
// Iterate through the block parameters until either one is found that is not
@@ -583,7 +583,7 @@ static bool checkOpenCLEnqueueVariadicArgs(Sema &S, CallExpr *TheCall,
const BlockPointerType *BPT =
cast<BlockPointerType>(BlockArg->getType().getCanonicalType());
unsigned NumBlockParams =
- BPT->getPointeeType()->getAs<FunctionProtoType>()->getNumParams();
+ BPT->getPointeeType()->castAs<FunctionProtoType>()->getNumParams();
unsigned TotalNumArgs = TheCall->getNumArgs();
// For each argument passed to the block, a corresponding uint needs to
@@ -629,7 +629,9 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
unsigned NumArgs = TheCall->getNumArgs();
if (NumArgs < 4) {
- S.Diag(TheCall->getBeginLoc(), diag::err_typecheck_call_too_few_args);
+ S.Diag(TheCall->getBeginLoc(),
+ diag::err_typecheck_call_too_few_args_at_least)
+ << 0 << 4 << NumArgs;
return true;
}
@@ -674,7 +676,7 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
// we have a block type, check the prototype
const BlockPointerType *BPT =
cast<BlockPointerType>(Arg3->getType().getCanonicalType());
- if (BPT->getPointeeType()->getAs<FunctionProtoType>()->getNumParams() > 0) {
+ if (BPT->getPointeeType()->castAs<FunctionProtoType>()->getNumParams() > 0) {
S.Diag(Arg3->getBeginLoc(),
diag::err_opencl_enqueue_kernel_blocks_no_args);
return true;
@@ -1179,6 +1181,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI__builtin_alloca_with_align:
if (SemaBuiltinAllocaWithAlign(TheCall))
return ExprError();
+ LLVM_FALLTHROUGH;
+ case Builtin::BI__builtin_alloca:
+ Diag(TheCall->getBeginLoc(), diag::warn_alloca)
+ << TheCall->getDirectCallee();
break;
case Builtin::BI__assume:
case Builtin::BI__builtin_assume:
@@ -1534,6 +1540,11 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
break;
+ case llvm::Triple::bpfeb:
+ case llvm::Triple::bpfel:
+ if (CheckBPFBuiltinFunctionCall(BuiltinID, TheCall))
+ return ExprError();
+ break;
case llvm::Triple::hexagon:
if (CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();
@@ -1928,11 +1939,46 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
case AArch64::BI__builtin_arm_dmb:
case AArch64::BI__builtin_arm_dsb:
case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break;
+ case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break;
}
return SemaBuiltinConstantArgRange(TheCall, i, l, u + l);
}
+bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID,
+ CallExpr *TheCall) {
+ assert(BuiltinID == BPF::BI__builtin_preserve_field_info &&
+ "unexpected ARM builtin");
+
+ if (checkArgCount(*this, TheCall, 2))
+ return true;
+
+ // The first argument needs to be a record field access.
+ // If it is an array element access, we delay decision
+ // to BPF backend to check whether the access is a
+ // field access or not.
+ Expr *Arg = TheCall->getArg(0);
+ if (Arg->getType()->getAsPlaceholderType() ||
+ (Arg->IgnoreParens()->getObjectKind() != OK_BitField &&
+ !dyn_cast<MemberExpr>(Arg->IgnoreParens()) &&
+ !dyn_cast<ArraySubscriptExpr>(Arg->IgnoreParens()))) {
+ Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_field)
+ << 1 << Arg->getSourceRange();
+ return true;
+ }
+
+ // The second argument needs to be a constant int
+ llvm::APSInt Value;
+ if (!TheCall->getArg(1)->isIntegerConstantExpr(Value, Context)) {
+ Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_const)
+ << 2 << Arg->getSourceRange();
+ return true;
+ }
+
+ TheCall->setType(Context.UnsignedIntTy);
+ return false;
+}
+
bool Sema::CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) {
struct BuiltinAndString {
unsigned BuiltinID;
@@ -3213,6 +3259,8 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case PPC::BI__builtin_altivec_crypto_vshasigmad:
return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) ||
SemaBuiltinConstantArgRange(TheCall, 2, 0, 15);
+ case PPC::BI__builtin_altivec_dss:
+ return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3);
case PPC::BI__builtin_tbegin:
case PPC::BI__builtin_tend: i = 0; l = 0; u = 1; break;
case PPC::BI__builtin_tsr: i = 0; l = 0; u = 7; break;
@@ -3222,6 +3270,11 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case PPC::BI__builtin_tabortdci:
return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) ||
SemaBuiltinConstantArgRange(TheCall, 2, 0, 31);
+ case PPC::BI__builtin_altivec_dst:
+ case PPC::BI__builtin_altivec_dstt:
+ case PPC::BI__builtin_altivec_dstst:
+ case PPC::BI__builtin_altivec_dststt:
+ return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3);
case PPC::BI__builtin_vsx_xxpermdi:
case PPC::BI__builtin_vsx_xxsldwi:
return SemaBuiltinVSX(TheCall);
@@ -3532,9 +3585,11 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) {
// Make sure rounding mode is either ROUND_CUR_DIRECTION or ROUND_NO_EXC bit
// is set. If the intrinsic has rounding control(bits 1:0), make sure its only
- // combined with ROUND_NO_EXC.
+ // combined with ROUND_NO_EXC. If the intrinsic does not have rounding
+ // control, allow ROUND_NO_EXC and ROUND_CUR_DIRECTION together.
if (Result == 4/*ROUND_CUR_DIRECTION*/ ||
Result == 8/*ROUND_NO_EXC*/ ||
+ (!HasRC && Result == 12/*ROUND_CUR_DIRECTION|ROUND_NO_EXC*/) ||
(HasRC && Result.getZExtValue() >= 8 && Result.getZExtValue() <= 11))
return false;
@@ -4449,7 +4504,16 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
AtomicExpr::AtomicOp Op) {
CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+ MultiExprArg Args{TheCall->getArgs(), TheCall->getNumArgs()};
+ return BuildAtomicExpr({TheCall->getBeginLoc(), TheCall->getEndLoc()},
+ DRE->getSourceRange(), TheCall->getRParenLoc(), Args,
+ Op);
+}
+ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
+ SourceLocation RParenLoc, MultiExprArg Args,
+ AtomicExpr::AtomicOp Op,
+ AtomicArgumentOrder ArgOrder) {
// All the non-OpenCL operations take one of the following forms.
// The OpenCL operations take the __c11 forms with one extra argument for
// synchronization scope.
@@ -4596,21 +4660,21 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
if (IsOpenCL && Op != AtomicExpr::AO__opencl_atomic_init)
++AdjustedNumArgs;
// Check we have the right number of arguments.
- if (TheCall->getNumArgs() < AdjustedNumArgs) {
- Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args)
- << 0 << AdjustedNumArgs << TheCall->getNumArgs()
- << TheCall->getCallee()->getSourceRange();
+ if (Args.size() < AdjustedNumArgs) {
+ Diag(CallRange.getEnd(), diag::err_typecheck_call_too_few_args)
+ << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size())
+ << ExprRange;
return ExprError();
- } else if (TheCall->getNumArgs() > AdjustedNumArgs) {
- Diag(TheCall->getArg(AdjustedNumArgs)->getBeginLoc(),
+ } else if (Args.size() > AdjustedNumArgs) {
+ Diag(Args[AdjustedNumArgs]->getBeginLoc(),
diag::err_typecheck_call_too_many_args)
- << 0 << AdjustedNumArgs << TheCall->getNumArgs()
- << TheCall->getCallee()->getSourceRange();
+ << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size())
+ << ExprRange;
return ExprError();
}
// Inspect the first argument of the atomic operation.
- Expr *Ptr = TheCall->getArg(0);
+ Expr *Ptr = Args[0];
ExprResult ConvertedPtr = DefaultFunctionArrayLvalueConversion(Ptr);
if (ConvertedPtr.isInvalid())
return ExprError();
@@ -4618,7 +4682,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
Ptr = ConvertedPtr.get();
const PointerType *pointerType = Ptr->getType()->getAs<PointerType>();
if (!pointerType) {
- Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)
+ Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
@@ -4628,21 +4692,21 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
QualType ValType = AtomTy; // 'C'
if (IsC11) {
if (!AtomTy->isAtomicType()) {
- Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_atomic)
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic)
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
if ((Form != Load && Form != LoadCopy && AtomTy.isConstQualified()) ||
AtomTy.getAddressSpace() == LangAS::opencl_constant) {
- Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_non_const_atomic)
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_atomic)
<< (AtomTy.isConstQualified() ? 0 : 1) << Ptr->getType()
<< Ptr->getSourceRange();
return ExprError();
}
- ValType = AtomTy->getAs<AtomicType>()->getValueType();
+ ValType = AtomTy->castAs<AtomicType>()->getValueType();
} else if (Form != Load && Form != LoadCopy) {
if (ValType.isConstQualified()) {
- Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_non_const_pointer)
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_pointer)
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
@@ -4653,7 +4717,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// gcc does not enforce these rules for GNU atomics, but we do so for sanity.
if (IsAddSub && !ValType->isIntegerType()
&& !ValType->isPointerType()) {
- Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_atomic_int_or_ptr)
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_or_ptr)
<< IsC11 << Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
@@ -4661,12 +4725,12 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
const BuiltinType *BT = ValType->getAs<BuiltinType>();
if (!BT || (BT->getKind() != BuiltinType::Int &&
BT->getKind() != BuiltinType::UInt)) {
- Diag(DRE->getBeginLoc(), diag::err_atomic_op_needs_int32_or_ptr);
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_int32_or_ptr);
return ExprError();
}
}
if (!IsAddSub && !IsMinMax && !ValType->isIntegerType()) {
- Diag(DRE->getBeginLoc(), diag::err_atomic_op_bitwise_needs_atomic_int)
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_bitwise_needs_atomic_int)
<< IsC11 << Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
@@ -4678,7 +4742,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
} 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->getBeginLoc(), diag::err_atomic_op_needs_atomic_int_or_ptr)
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_or_ptr)
<< IsC11 << Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
@@ -4687,7 +4751,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
!AtomTy->isScalarType()) {
// 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->getBeginLoc(), diag::err_atomic_op_needs_trivial_copy)
+ Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_trivial_copy)
<< Ptr->getType() << Ptr->getSourceRange();
return ExprError();
}
@@ -4703,7 +4767,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
case Qualifiers::OCL_Autoreleasing:
// FIXME: Can this happen? By this point, ValType should be known
// to be trivially copyable.
- Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership)
+ Diag(ExprRange.getBegin(), diag::err_arc_atomic_ownership)
<< ValType << Ptr->getSourceRange();
return ExprError();
}
@@ -4730,19 +4794,56 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
IsPassedByAddress = true;
}
+ SmallVector<Expr *, 5> APIOrderedArgs;
+ if (ArgOrder == Sema::AtomicArgumentOrder::AST) {
+ APIOrderedArgs.push_back(Args[0]);
+ switch (Form) {
+ case Init:
+ case Load:
+ APIOrderedArgs.push_back(Args[1]); // Val1/Order
+ break;
+ case LoadCopy:
+ case Copy:
+ case Arithmetic:
+ case Xchg:
+ APIOrderedArgs.push_back(Args[2]); // Val1
+ APIOrderedArgs.push_back(Args[1]); // Order
+ break;
+ case GNUXchg:
+ APIOrderedArgs.push_back(Args[2]); // Val1
+ APIOrderedArgs.push_back(Args[3]); // Val2
+ APIOrderedArgs.push_back(Args[1]); // Order
+ break;
+ case C11CmpXchg:
+ APIOrderedArgs.push_back(Args[2]); // Val1
+ APIOrderedArgs.push_back(Args[4]); // Val2
+ APIOrderedArgs.push_back(Args[1]); // Order
+ APIOrderedArgs.push_back(Args[3]); // OrderFail
+ break;
+ case GNUCmpXchg:
+ APIOrderedArgs.push_back(Args[2]); // Val1
+ APIOrderedArgs.push_back(Args[4]); // Val2
+ APIOrderedArgs.push_back(Args[5]); // Weak
+ APIOrderedArgs.push_back(Args[1]); // Order
+ APIOrderedArgs.push_back(Args[3]); // OrderFail
+ break;
+ }
+ } else
+ APIOrderedArgs.append(Args.begin(), Args.end());
+
// The first argument's non-CV pointer type is used to deduce the type of
// subsequent arguments, except for:
// - weak flag (always converted to bool)
// - memory order (always converted to int)
// - scope (always converted to int)
- for (unsigned i = 0; i != TheCall->getNumArgs(); ++i) {
+ for (unsigned i = 0; i != APIOrderedArgs.size(); ++i) {
QualType Ty;
if (i < NumVals[Form] + 1) {
switch (i) {
case 0:
// The first argument is always a pointer. It has a fixed type.
// It is always dereferenced, a nullptr is undefined.
- CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getBeginLoc());
+ CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin());
// Nothing else to do: we already know all we want about this pointer.
continue;
case 1:
@@ -4754,16 +4855,18 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
if (Form == Init || (Form == Arithmetic && ValType->isIntegerType()))
Ty = ValType;
else if (Form == Copy || Form == Xchg) {
- if (IsPassedByAddress)
+ if (IsPassedByAddress) {
// The value pointer is always dereferenced, a nullptr is undefined.
- CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getBeginLoc());
+ CheckNonNullArgument(*this, APIOrderedArgs[i],
+ ExprRange.getBegin());
+ }
Ty = ByValType;
} else if (Form == Arithmetic)
Ty = Context.getPointerDiffType();
else {
- Expr *ValArg = TheCall->getArg(i);
+ Expr *ValArg = APIOrderedArgs[i];
// The value pointer is always dereferenced, a nullptr is undefined.
- CheckNonNullArgument(*this, ValArg, DRE->getBeginLoc());
+ CheckNonNullArgument(*this, ValArg, ExprRange.getBegin());
LangAS AS = LangAS::Default;
// Keep address space of non-atomic pointer type.
if (const PointerType *PtrTy =
@@ -4778,7 +4881,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// The third argument to compare_exchange / GNU exchange is the desired
// value, either by-value (for the C11 and *_n variant) or as a pointer.
if (IsPassedByAddress)
- CheckNonNullArgument(*this, TheCall->getArg(i), DRE->getBeginLoc());
+ CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin());
Ty = ByValType;
break;
case 3:
@@ -4793,11 +4896,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
InitializedEntity Entity =
InitializedEntity::InitializeParameter(Context, Ty, false);
- ExprResult Arg = TheCall->getArg(i);
+ ExprResult Arg = APIOrderedArgs[i];
Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
if (Arg.isInvalid())
return true;
- TheCall->setArg(i, Arg.get());
+ APIOrderedArgs[i] = Arg.get();
}
// Permute the arguments into a 'consistent' order.
@@ -4806,36 +4909,36 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
switch (Form) {
case Init:
// Note, AtomicExpr::getVal1() has a special case for this atomic.
- SubExprs.push_back(TheCall->getArg(1)); // Val1
+ SubExprs.push_back(APIOrderedArgs[1]); // Val1
break;
case Load:
- SubExprs.push_back(TheCall->getArg(1)); // Order
+ SubExprs.push_back(APIOrderedArgs[1]); // Order
break;
case LoadCopy:
case Copy:
case Arithmetic:
case Xchg:
- SubExprs.push_back(TheCall->getArg(2)); // Order
- SubExprs.push_back(TheCall->getArg(1)); // Val1
+ SubExprs.push_back(APIOrderedArgs[2]); // Order
+ SubExprs.push_back(APIOrderedArgs[1]); // Val1
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
+ SubExprs.push_back(APIOrderedArgs[3]); // Order
+ SubExprs.push_back(APIOrderedArgs[1]); // Val1
+ SubExprs.push_back(APIOrderedArgs[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
+ SubExprs.push_back(APIOrderedArgs[3]); // Order
+ SubExprs.push_back(APIOrderedArgs[1]); // Val1
+ SubExprs.push_back(APIOrderedArgs[4]); // OrderFail
+ SubExprs.push_back(APIOrderedArgs[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
+ SubExprs.push_back(APIOrderedArgs[4]); // Order
+ SubExprs.push_back(APIOrderedArgs[1]); // Val1
+ SubExprs.push_back(APIOrderedArgs[5]); // OrderFail
+ SubExprs.push_back(APIOrderedArgs[2]); // Val2
+ SubExprs.push_back(APIOrderedArgs[3]); // Weak
break;
}
@@ -4849,7 +4952,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
}
if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) {
- auto *Scope = TheCall->getArg(TheCall->getNumArgs() - 1);
+ auto *Scope = Args[Args.size() - 1];
llvm::APSInt Result(32);
if (Scope->isIntegerConstantExpr(Result, Context) &&
!ScopeModel->isValid(Result.getZExtValue())) {
@@ -4859,9 +4962,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
SubExprs.push_back(Scope);
}
- AtomicExpr *AE =
- new (Context) AtomicExpr(TheCall->getCallee()->getBeginLoc(), SubExprs,
- ResultType, Op, TheCall->getRParenLoc());
+ AtomicExpr *AE = new (Context)
+ AtomicExpr(ExprRange.getBegin(), SubExprs, ResultType, Op, RParenLoc);
if ((Op == AtomicExpr::AO__c11_atomic_load ||
Op == AtomicExpr::AO__c11_atomic_store ||
@@ -5410,7 +5512,7 @@ static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) {
if (IsX64 || IsAArch64) {
CallingConv CC = CC_C;
if (const FunctionDecl *FD = S.getCurFunctionDecl())
- CC = FD->getType()->getAs<FunctionType>()->getCallConv();
+ CC = FD->getType()->castAs<FunctionType>()->getCallConv();
if (IsMSVAStart) {
// Don't allow this in System V ABI functions.
if (CC == CC_X86_64SysV || (!IsWindows && CC != CC_Win64))
@@ -5540,7 +5642,7 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
return false;
if (!Type->isEnumeralType())
return true;
- const EnumDecl *ED = Type->getAs<EnumType>()->getDecl();
+ const EnumDecl *ED = Type->castAs<EnumType>()->getDecl();
return !(ED &&
Context.typesAreCompatible(ED->getPromotionType(), Type));
}()) {
@@ -5780,7 +5882,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc()));
- numElements = LHSType->getAs<VectorType>()->getNumElements();
+ numElements = LHSType->castAs<VectorType>()->getNumElements();
unsigned numResElements = TheCall->getNumArgs() - 2;
// Check to see if we have a call with 2 vector arguments, the unary shuffle
@@ -5788,7 +5890,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
// same number of elts as lhs.
if (TheCall->getNumArgs() == 2) {
if (!RHSType->hasIntegerRepresentation() ||
- RHSType->getAs<VectorType>()->getNumElements() != numElements)
+ RHSType->castAs<VectorType>()->getNumElements() != numElements)
return ExprError(Diag(TheCall->getBeginLoc(),
diag::err_vec_builtin_incompatible_vector)
<< TheCall->getDirectCallee()
@@ -5801,7 +5903,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc()));
} else if (numElements != numResElements) {
- QualType eltType = LHSType->getAs<VectorType>()->getElementType();
+ QualType eltType = LHSType->castAs<VectorType>()->getElementType();
resType = Context.getVectorType(eltType, numResElements,
VectorType::GenericVector);
}
@@ -5858,8 +5960,8 @@ ExprResult Sema::SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
diag::err_convertvector_non_vector_type));
if (!SrcTy->isDependentType() && !DstTy->isDependentType()) {
- unsigned SrcElts = SrcTy->getAs<VectorType>()->getNumElements();
- unsigned DstElts = DstTy->getAs<VectorType>()->getNumElements();
+ unsigned SrcElts = SrcTy->castAs<VectorType>()->getNumElements();
+ unsigned DstElts = DstTy->castAs<VectorType>()->getNumElements();
if (SrcElts != DstElts)
return ExprError(Diag(BuiltinLoc,
diag::err_convertvector_incompatible_vector)
@@ -5961,6 +6063,12 @@ bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) {
if (!Result.isPowerOf2())
return Diag(TheCall->getBeginLoc(), diag::err_alignment_not_power_of_two)
<< Arg->getSourceRange();
+
+ // Alignment calculations can wrap around if it's greater than 2**29.
+ unsigned MaximumAlignment = 536870912;
+ if (Result > MaximumAlignment)
+ Diag(TheCall->getBeginLoc(), diag::warn_assume_aligned_too_great)
+ << Arg->getSourceRange() << MaximumAlignment;
}
if (NumArgs > 2) {
@@ -6570,7 +6678,8 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr,
bool inFunctionCall,
Sema::VariadicCallType CallType,
llvm::SmallBitVector &CheckedVarArgs,
- UncoveredArgHandler &UncoveredArg);
+ UncoveredArgHandler &UncoveredArg,
+ bool IgnoreStringsWithoutSpecifiers);
// Determine if an expression is a string literal or constant string.
// If this function returns false on the arguments to a function expecting a
@@ -6583,7 +6692,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
Sema::VariadicCallType CallType, bool InFunctionCall,
llvm::SmallBitVector &CheckedVarArgs,
UncoveredArgHandler &UncoveredArg,
- llvm::APSInt Offset) {
+ llvm::APSInt Offset,
+ bool IgnoreStringsWithoutSpecifiers = false) {
if (S.isConstantEvaluated())
return SLCT_NotALiteral;
tryAgain:
@@ -6634,17 +6744,17 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
Left = checkFormatStringExpr(S, C->getTrueExpr(), Args,
HasVAListArg, format_idx, firstDataArg,
Type, CallType, InFunctionCall,
- CheckedVarArgs, UncoveredArg, Offset);
+ CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
if (Left == SLCT_NotALiteral || !CheckRight) {
return Left;
}
}
- StringLiteralCheckType Right =
- checkFormatStringExpr(S, C->getFalseExpr(), Args,
- HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall, CheckedVarArgs,
- UncoveredArg, Offset);
+ StringLiteralCheckType Right = checkFormatStringExpr(
+ S, C->getFalseExpr(), Args, HasVAListArg, format_idx, firstDataArg,
+ Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
return (CheckLeft && Left < Right) ? Left : Right;
}
@@ -6748,7 +6858,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
StringLiteralCheckType Result = checkFormatStringExpr(
S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
- CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset);
+ CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
if (IsFirst) {
CommonResult = Result;
IsFirst = false;
@@ -6766,7 +6877,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
HasVAListArg, format_idx,
firstDataArg, Type, CallType,
InFunctionCall, CheckedVarArgs,
- UncoveredArg, Offset);
+ UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
}
}
}
@@ -6775,12 +6887,28 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
}
case Stmt::ObjCMessageExprClass: {
const auto *ME = cast<ObjCMessageExpr>(E);
- if (const auto *ND = ME->getMethodDecl()) {
- if (const auto *FA = ND->getAttr<FormatArgAttr>()) {
+ if (const auto *MD = ME->getMethodDecl()) {
+ if (const auto *FA = MD->getAttr<FormatArgAttr>()) {
+ // As a special case heuristic, if we're using the method -[NSBundle
+ // localizedStringForKey:value:table:], ignore any key strings that lack
+ // format specifiers. The idea is that if the key doesn't have any
+ // format specifiers then its probably just a key to map to the
+ // localized strings. If it does have format specifiers though, then its
+ // likely that the text of the key is the format string in the
+ // programmer's language, and should be checked.
+ const ObjCInterfaceDecl *IFace;
+ if (MD->isInstanceMethod() && (IFace = MD->getClassInterface()) &&
+ IFace->getIdentifier()->isStr("NSBundle") &&
+ MD->getSelector().isKeywordSelector(
+ {"localizedStringForKey", "value", "table"})) {
+ IgnoreStringsWithoutSpecifiers = true;
+ }
+
const Expr *Arg = ME->getArg(FA->getFormatIdx().getASTIndex());
return checkFormatStringExpr(
S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
- CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset);
+ CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset,
+ IgnoreStringsWithoutSpecifiers);
}
}
@@ -6804,7 +6932,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
FormatStringLiteral FStr(StrE, Offset.sextOrTrunc(64).getSExtValue());
CheckFormatString(S, &FStr, E, Args, HasVAListArg, format_idx,
firstDataArg, Type, InFunctionCall, CallType,
- CheckedVarArgs, UncoveredArg);
+ CheckedVarArgs, UncoveredArg,
+ IgnoreStringsWithoutSpecifiers);
return SLCT_CheckedLiteral;
}
@@ -8072,9 +8201,23 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
ExprTy = TET->getUnderlyingExpr()->getType();
}
- const analyze_printf::ArgType::MatchKind Match =
- AT.matchesType(S.Context, ExprTy);
- bool Pedantic = Match == analyze_printf::ArgType::NoMatchPedantic;
+ // Diagnose attempts to print a boolean value as a character. Unlike other
+ // -Wformat diagnostics, this is fine from a type perspective, but it still
+ // doesn't make sense.
+ if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::cArg &&
+ E->isKnownToHaveBooleanValue()) {
+ const CharSourceRange &CSR =
+ getSpecifierRange(StartSpecifier, SpecifierLen);
+ SmallString<4> FSString;
+ llvm::raw_svector_ostream os(FSString);
+ FS.toString(os);
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_bool_as_character)
+ << FSString,
+ E->getExprLoc(), false, CSR);
+ return true;
+ }
+
+ analyze_printf::ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy);
if (Match == analyze_printf::ArgType::Match)
return true;
@@ -8093,9 +8236,14 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// function.
if (ICE->getType() == S.Context.IntTy ||
ICE->getType() == S.Context.UnsignedIntTy) {
- // All further checking is done on the subexpression.
- if (AT.matchesType(S.Context, ExprTy))
+ // All further checking is done on the subexpression
+ const analyze_printf::ArgType::MatchKind ImplicitMatch =
+ AT.matchesType(S.Context, ExprTy);
+ if (ImplicitMatch == analyze_printf::ArgType::Match)
return true;
+ if (ImplicitMatch == ArgType::NoMatchPedantic ||
+ ImplicitMatch == ArgType::NoMatchTypeConfusion)
+ Match = ImplicitMatch;
}
}
} else if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E)) {
@@ -8157,7 +8305,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if ((CastTyName == "NSInteger" || CastTyName == "NSUInteger") &&
(AT.isSizeT() || AT.isPtrdiffT()) &&
AT.matchesType(S.Context, CastTy))
- Pedantic = true;
+ Match = ArgType::NoMatchPedantic;
IntendedTy = CastTy;
ShouldNotPrintDirectly = true;
}
@@ -8177,10 +8325,20 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen);
if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) {
- unsigned Diag =
- Pedantic
- ? diag::warn_format_conversion_argument_type_mismatch_pedantic
- : diag::warn_format_conversion_argument_type_mismatch;
+ unsigned Diag;
+ switch (Match) {
+ case ArgType::Match: llvm_unreachable("expected non-matching");
+ case ArgType::NoMatchPedantic:
+ Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
+ break;
+ case ArgType::NoMatchTypeConfusion:
+ Diag = diag::warn_format_conversion_argument_type_mismatch_confusion;
+ break;
+ case ArgType::NoMatch:
+ Diag = diag::warn_format_conversion_argument_type_mismatch;
+ break;
+ }
+
// In this case, the specifier is wrong and should be changed to match
// the argument.
EmitFormatDiagnostic(S.PDiag(Diag)
@@ -8236,7 +8394,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
Name = TypedefTy->getDecl()->getName();
else
Name = CastTyName;
- unsigned Diag = Pedantic
+ unsigned Diag = Match == ArgType::NoMatchPedantic
? diag::warn_format_argument_needs_cast_pedantic
: diag::warn_format_argument_needs_cast;
EmitFormatDiagnostic(S.PDiag(Diag) << Name << IntendedTy << IsEnum
@@ -8263,10 +8421,19 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
switch (S.isValidVarArgType(ExprTy)) {
case Sema::VAK_Valid:
case Sema::VAK_ValidInCXX11: {
- unsigned Diag =
- Pedantic
- ? diag::warn_format_conversion_argument_type_mismatch_pedantic
- : diag::warn_format_conversion_argument_type_mismatch;
+ unsigned Diag;
+ switch (Match) {
+ case ArgType::Match: llvm_unreachable("expected non-matching");
+ case ArgType::NoMatchPedantic:
+ Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
+ break;
+ case ArgType::NoMatchTypeConfusion:
+ Diag = diag::warn_format_conversion_argument_type_mismatch_confusion;
+ break;
+ case ArgType::NoMatch:
+ Diag = diag::warn_format_conversion_argument_type_mismatch;
+ break;
+ }
EmitFormatDiagnostic(
S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy
@@ -8495,7 +8662,8 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr,
bool inFunctionCall,
Sema::VariadicCallType CallType,
llvm::SmallBitVector &CheckedVarArgs,
- UncoveredArgHandler &UncoveredArg) {
+ UncoveredArgHandler &UncoveredArg,
+ bool IgnoreStringsWithoutSpecifiers) {
// CHECK: is the format string a wide literal?
if (!FExpr->isAscii() && !FExpr->isUTF8()) {
CheckFormatHandler::EmitFormatDiagnostic(
@@ -8516,6 +8684,11 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr,
size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size());
const unsigned numDataArgs = Args.size() - firstDataArg;
+ if (IgnoreStringsWithoutSpecifiers &&
+ !analyze_format_string::parseFormatStringHasFormattingSpecifiers(
+ Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo()))
+ return;
+
// Emit a warning if the string literal is truncated and does not contain an
// embedded null character.
if (TypeSize <= StrRef.size() &&
@@ -10195,7 +10368,8 @@ static bool IsSameFloatAfterCast(const APValue &value,
IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
}
-static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC);
+static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC,
+ bool IsListInit = false);
static bool IsEnumConstOrFromMacro(Sema &S, Expr *E) {
// Suppress cases where we are comparing against an enum constant.
@@ -10627,7 +10801,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
return false;
if (BitfieldType->isEnumeralType()) {
- EnumDecl *BitfieldEnumDecl = BitfieldType->getAs<EnumType>()->getDecl();
+ EnumDecl *BitfieldEnumDecl = BitfieldType->castAs<EnumType>()->getDecl();
// If the underlying enum type was not explicitly specified as an unsigned
// type and the enum contain only positive values, MSVC++ will cause an
// inconsistency by storing this as a signed type.
@@ -10792,6 +10966,26 @@ static void DiagnoseImpCast(Sema &S, Expr *E, QualType T,
DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow);
}
+static bool isObjCSignedCharBool(Sema &S, QualType Ty) {
+ return Ty->isSpecificBuiltinType(BuiltinType::SChar) &&
+ S.getLangOpts().ObjC && S.NSAPIObj->isObjCBOOLType(Ty);
+}
+
+static void adornObjCBoolConversionDiagWithTernaryFixit(
+ Sema &S, Expr *SourceExpr, const Sema::SemaDiagnosticBuilder &Builder) {
+ Expr *Ignored = SourceExpr->IgnoreImplicit();
+ if (const auto *OVE = dyn_cast<OpaqueValueExpr>(Ignored))
+ Ignored = OVE->getSourceExpr();
+ bool NeedsParens = isa<AbstractConditionalOperator>(Ignored) ||
+ isa<BinaryOperator>(Ignored) ||
+ isa<CXXOperatorCallExpr>(Ignored);
+ SourceLocation EndLoc = S.getLocForEndOfToken(SourceExpr->getEndLoc());
+ if (NeedsParens)
+ Builder << FixItHint::CreateInsertion(SourceExpr->getBeginLoc(), "(")
+ << FixItHint::CreateInsertion(EndLoc, ")");
+ Builder << FixItHint::CreateInsertion(EndLoc, " ? YES : NO");
+}
+
/// Diagnose an implicit cast from a floating point value to an integer value.
static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
SourceLocation CContext) {
@@ -10811,6 +11005,13 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
bool IsConstant =
E->EvaluateAsFloat(Value, S.Context, Expr::SE_AllowSideEffects);
if (!IsConstant) {
+ if (isObjCSignedCharBool(S, T)) {
+ return adornObjCBoolConversionDiagWithTernaryFixit(
+ S, E,
+ S.Diag(CContext, diag::warn_impcast_float_to_objc_signed_char_bool)
+ << E->getType());
+ }
+
return DiagnoseImpCast(S, E, T, CContext,
diag::warn_impcast_float_integer, PruneWarnings);
}
@@ -10822,6 +11023,23 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
llvm::APFloat::opStatus Result = Value.convertToInteger(
IntegerValue, llvm::APFloat::rmTowardZero, &isExact);
+ // FIXME: Force the precision of the source value down so we don't print
+ // digits which are usually useless (we don't really care here if we
+ // truncate a digit by accident in edge cases). Ideally, APFloat::toString
+ // would automatically print the shortest representation, but it's a bit
+ // tricky to implement.
+ SmallString<16> PrettySourceValue;
+ unsigned precision = llvm::APFloat::semanticsPrecision(Value.getSemantics());
+ precision = (precision * 59 + 195) / 196;
+ Value.toString(PrettySourceValue, precision);
+
+ if (isObjCSignedCharBool(S, T) && IntegerValue != 0 && IntegerValue != 1) {
+ return adornObjCBoolConversionDiagWithTernaryFixit(
+ S, E,
+ S.Diag(CContext, diag::warn_impcast_constant_value_to_objc_bool)
+ << PrettySourceValue);
+ }
+
if (Result == llvm::APFloat::opOK && isExact) {
if (IsLiteral) return;
return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer,
@@ -10865,16 +11083,6 @@ static void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
DiagID = diag::warn_impcast_float_to_integer;
}
- // FIXME: Force the precision of the source value down so we don't print
- // digits which are usually useless (we don't really care here if we
- // truncate a digit by accident in edge cases). Ideally, APFloat::toString
- // would automatically print the shortest representation, but it's a bit
- // tricky to implement.
- SmallString<16> PrettySourceValue;
- unsigned precision = llvm::APFloat::semanticsPrecision(Value.getSemantics());
- precision = (precision * 59 + 195) / 196;
- Value.toString(PrettySourceValue, precision);
-
SmallString<16> PrettyTargetValue;
if (IsBool)
PrettyTargetValue = Value.isZero() ? "false" : "true";
@@ -11151,14 +11359,85 @@ static bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T,
return true;
}
-static bool isObjCSignedCharBool(Sema &S, QualType Ty) {
- return Ty->isSpecificBuiltinType(BuiltinType::SChar) &&
- S.getLangOpts().ObjC && S.NSAPIObj->isObjCBOOLType(Ty);
+static const IntegerLiteral *getIntegerLiteral(Expr *E) {
+ const auto *IL = dyn_cast<IntegerLiteral>(E);
+ if (!IL) {
+ if (auto *UO = dyn_cast<UnaryOperator>(E)) {
+ if (UO->getOpcode() == UO_Minus)
+ return dyn_cast<IntegerLiteral>(UO->getSubExpr());
+ }
+ }
+
+ return IL;
}
-static void
-CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
- bool *ICContext = nullptr) {
+static void CheckConditionalWithEnumTypes(Sema &S, SourceLocation Loc,
+ Expr *LHS, Expr *RHS) {
+ QualType LHSStrippedType = LHS->IgnoreParenImpCasts()->getType();
+ QualType RHSStrippedType = RHS->IgnoreParenImpCasts()->getType();
+
+ const auto *LHSEnumType = LHSStrippedType->getAs<EnumType>();
+ if (!LHSEnumType)
+ return;
+ const auto *RHSEnumType = RHSStrippedType->getAs<EnumType>();
+ if (!RHSEnumType)
+ return;
+
+ // Ignore anonymous enums.
+ if (!LHSEnumType->getDecl()->hasNameForLinkage())
+ return;
+ if (!RHSEnumType->getDecl()->hasNameForLinkage())
+ return;
+
+ if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType))
+ return;
+
+ S.Diag(Loc, diag::warn_conditional_mixed_enum_types)
+ << LHSStrippedType << RHSStrippedType << LHS->getSourceRange()
+ << RHS->getSourceRange();
+}
+
+static void DiagnoseIntInBoolContext(Sema &S, Expr *E) {
+ E = E->IgnoreParenImpCasts();
+ SourceLocation ExprLoc = E->getExprLoc();
+
+ if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
+ BinaryOperator::Opcode Opc = BO->getOpcode();
+ Expr::EvalResult Result;
+ // Do not diagnose unsigned shifts.
+ if (Opc == BO_Shl) {
+ const auto *LHS = getIntegerLiteral(BO->getLHS());
+ const auto *RHS = getIntegerLiteral(BO->getRHS());
+ if (LHS && LHS->getValue() == 0)
+ S.Diag(ExprLoc, diag::warn_left_shift_always) << 0;
+ else if (!E->isValueDependent() && LHS && RHS &&
+ RHS->getValue().isNonNegative() &&
+ E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects))
+ S.Diag(ExprLoc, diag::warn_left_shift_always)
+ << (Result.Val.getInt() != 0);
+ else if (E->getType()->isSignedIntegerType())
+ S.Diag(ExprLoc, diag::warn_left_shift_in_bool_context) << E;
+ }
+ }
+
+ if (const auto *CO = dyn_cast<ConditionalOperator>(E)) {
+ const auto *LHS = getIntegerLiteral(CO->getTrueExpr());
+ const auto *RHS = getIntegerLiteral(CO->getFalseExpr());
+ if (!LHS || !RHS)
+ return;
+ if ((LHS->getValue() == 0 || LHS->getValue() == 1) &&
+ (RHS->getValue() == 0 || RHS->getValue() == 1))
+ // Do not diagnose common idioms.
+ return;
+ if (LHS->getValue() != 0 && RHS->getValue() != 0)
+ S.Diag(ExprLoc, diag::warn_integer_constants_in_conditional_always_true);
+ }
+}
+
+static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
+ SourceLocation CC,
+ bool *ICContext = nullptr,
+ bool IsListInit = false) {
if (E->isTypeDependent() || E->isValueDependent()) return;
const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr();
@@ -11205,19 +11484,13 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
if (isObjCSignedCharBool(S, T) && Source->isIntegralType(S.Context)) {
Expr::EvalResult Result;
if (E->EvaluateAsInt(Result, S.getASTContext(),
- Expr::SE_AllowSideEffects) &&
- Result.Val.getInt() != 1 && Result.Val.getInt() != 0) {
- auto Builder = S.Diag(CC, diag::warn_impcast_constant_int_to_objc_bool)
- << Result.Val.getInt().toString(10);
- Expr *Ignored = E->IgnoreImplicit();
- bool NeedsParens = isa<AbstractConditionalOperator>(Ignored) ||
- isa<BinaryOperator>(Ignored) ||
- isa<CXXOperatorCallExpr>(Ignored);
- SourceLocation EndLoc = S.getLocForEndOfToken(E->getEndLoc());
- if (NeedsParens)
- Builder << FixItHint::CreateInsertion(E->getBeginLoc(), "(")
- << FixItHint::CreateInsertion(EndLoc, ")");
- Builder << FixItHint::CreateInsertion(EndLoc, " ? YES : NO");
+ Expr::SE_AllowSideEffects)) {
+ if (Result.Val.getInt() != 1 && Result.Val.getInt() != 0) {
+ adornObjCBoolConversionDiagWithTernaryFixit(
+ S, E,
+ S.Diag(CC, diag::warn_impcast_constant_value_to_objc_bool)
+ << Result.Val.getInt().toString(10));
+ }
return;
}
}
@@ -11400,10 +11673,61 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
}
}
+ // If we are casting an integer type to a floating point type without
+ // initialization-list syntax, we might lose accuracy if the floating
+ // point type has a narrower significand than the integer type.
+ if (SourceBT && TargetBT && SourceBT->isIntegerType() &&
+ TargetBT->isFloatingType() && !IsListInit) {
+ // Determine the number of precision bits in the source integer type.
+ IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated());
+ unsigned int SourcePrecision = SourceRange.Width;
+
+ // Determine the number of precision bits in the
+ // target floating point type.
+ unsigned int TargetPrecision = llvm::APFloatBase::semanticsPrecision(
+ S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)));
+
+ if (SourcePrecision > 0 && TargetPrecision > 0 &&
+ SourcePrecision > TargetPrecision) {
+
+ llvm::APSInt SourceInt;
+ if (E->isIntegerConstantExpr(SourceInt, S.Context)) {
+ // If the source integer is a constant, convert it to the target
+ // floating point type. Issue a warning if the value changes
+ // during the whole conversion.
+ llvm::APFloat TargetFloatValue(
+ S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)));
+ llvm::APFloat::opStatus ConversionStatus =
+ TargetFloatValue.convertFromAPInt(
+ SourceInt, SourceBT->isSignedInteger(),
+ llvm::APFloat::rmNearestTiesToEven);
+
+ if (ConversionStatus != llvm::APFloat::opOK) {
+ std::string PrettySourceValue = SourceInt.toString(10);
+ SmallString<32> PrettyTargetValue;
+ TargetFloatValue.toString(PrettyTargetValue, TargetPrecision);
+
+ S.DiagRuntimeBehavior(
+ E->getExprLoc(), E,
+ S.PDiag(diag::warn_impcast_integer_float_precision_constant)
+ << PrettySourceValue << PrettyTargetValue << E->getType() << T
+ << E->getSourceRange() << clang::SourceRange(CC));
+ }
+ } else {
+ // Otherwise, the implicit conversion may lose precision.
+ DiagnoseImpCast(S, E, T, CC,
+ diag::warn_impcast_integer_float_precision);
+ }
+ }
+ }
+
DiagnoseNullConversion(S, E, T, CC);
S.DiscardMisalignedMemberAddress(Target, E);
+ if (Target->isBooleanType())
+ DiagnoseIntInBoolContext(S, E);
+
if (!Source->isIntegerType() || !Target->isIntegerType())
return;
@@ -11412,6 +11736,14 @@ CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC,
if (Target->isSpecificBuiltinType(BuiltinType::Bool))
return;
+ if (isObjCSignedCharBool(S, T) && !Source->isCharType() &&
+ !E->isKnownToHaveBooleanValue()) {
+ return adornObjCBoolConversionDiagWithTernaryFixit(
+ S, E,
+ S.Diag(CC, diag::warn_impcast_int_to_objc_signed_char_bool)
+ << E->getType());
+ }
+
IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated());
IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target);
@@ -11556,6 +11888,11 @@ static void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
bool Suspicious = false;
CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious);
CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious);
+ CheckConditionalWithEnumTypes(S, E->getBeginLoc(), E->getTrueExpr(),
+ E->getFalseExpr());
+
+ if (T->isBooleanType())
+ DiagnoseIntInBoolContext(S, E);
// If -Wconversion would have warned about either of the candidates
// for a signedness conversion to the context type...
@@ -11590,14 +11927,27 @@ static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) {
/// AnalyzeImplicitConversions - Find and report any interesting
/// implicit conversions in the given expression. There are a couple
/// of competing diagnostics here, -Wconversion and -Wsign-compare.
-static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE,
- SourceLocation CC) {
+static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC,
+ bool IsListInit/*= false*/) {
QualType T = OrigE->getType();
Expr *E = OrigE->IgnoreParenImpCasts();
+ // Propagate whether we are in a C++ list initialization expression.
+ // If so, we do not issue warnings for implicit int-float conversion
+ // precision loss, because C++11 narrowing already handles it.
+ IsListInit =
+ IsListInit || (isa<InitListExpr>(OrigE) && S.getLangOpts().CPlusPlus);
+
if (E->isTypeDependent() || E->isValueDependent())
return;
+ if (const auto *UO = dyn_cast<UnaryOperator>(E))
+ if (UO->getOpcode() == UO_Not &&
+ UO->getSubExpr()->isKnownToHaveBooleanValue())
+ S.Diag(UO->getBeginLoc(), diag::warn_bitwise_negation_bool)
+ << OrigE->getSourceRange() << T->isBooleanType()
+ << FixItHint::CreateReplacement(UO->getBeginLoc(), "!");
+
// For conditional operators, we analyze the arguments as if they
// were being fed directly into the output.
if (isa<ConditionalOperator>(E)) {
@@ -11614,7 +11964,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE,
// The non-canonical typecheck is just an optimization;
// CheckImplicitConversion will filter out dead implicit conversions.
if (E->getType() != T)
- CheckImplicitConversion(S, E, T, CC);
+ CheckImplicitConversion(S, E, T, CC, nullptr, IsListInit);
// Now continue drilling into this expression.
@@ -11624,7 +11974,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE,
// FIXME: Use a more uniform representation for this.
for (auto *SE : POE->semantics())
if (auto *OVE = dyn_cast<OpaqueValueExpr>(SE))
- AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC);
+ AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC, IsListInit);
}
// Skip past explicit casts.
@@ -11632,7 +11982,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE,
E = CE->getSubExpr()->IgnoreParenImpCasts();
if (!CE->getType()->isVoidType() && E->getType()->isAtomicType())
S.Diag(E->getBeginLoc(), diag::warn_atomic_implicit_seq_cst);
- return AnalyzeImplicitConversions(S, E, CC);
+ return AnalyzeImplicitConversions(S, E, CC, IsListInit);
}
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
@@ -11671,7 +12021,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE,
// Ignore checking string literals that are in logical and operators.
// This is a common pattern for asserts.
continue;
- AnalyzeImplicitConversions(S, ChildExpr, CC);
+ AnalyzeImplicitConversions(S, ChildExpr, CC, IsListInit);
}
if (BO && BO->isLogicalOp()) {
@@ -12907,7 +13257,7 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
if (ND)
DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr,
- PDiag(diag::note_array_index_out_of_bounds)
+ PDiag(diag::note_array_declared_here)
<< ND->getDeclName());
}
@@ -14229,7 +14579,7 @@ void Sema::RefersToMemberWithReducedAlignment(
QualType BaseType = ME->getBase()->getType();
if (ME->isArrow())
BaseType = BaseType->getPointeeType();
- RecordDecl *RD = BaseType->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = BaseType->castAs<RecordType>()->getDecl();
if (RD->isInvalidDecl())
return;
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index e4bbee86e350..f24c3b234ff2 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -1185,6 +1185,9 @@ static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate,
const CXXMethodDecl &Incumbent,
const Qualifiers &ObjectQuals,
ExprValueKind ObjectKind) {
+ // Base/derived shadowing is handled elsewhere.
+ if (Candidate.getDeclContext() != Incumbent.getDeclContext())
+ return OverloadCompare::BothViable;
if (Candidate.isVariadic() != Incumbent.isVariadic() ||
Candidate.getNumParams() != Incumbent.getNumParams() ||
Candidate.getMinRequiredArguments() !=
diff --git a/lib/Sema/SemaConcept.cpp b/lib/Sema/SemaConcept.cpp
new file mode 100644
index 000000000000..848ccf543445
--- /dev/null
+++ b/lib/Sema/SemaConcept.cpp
@@ -0,0 +1,125 @@
+//===-- SemaConcept.cpp - Semantic Analysis for Constraints and Concepts --===//
+//
+// 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++ constraints and concepts.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Sema/TemplateDeduction.h"
+#include "clang/Sema/Template.h"
+#include "clang/AST/ExprCXX.h"
+using namespace clang;
+using namespace sema;
+
+bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) {
+ // C++2a [temp.constr.atomic]p1
+ // ..E shall be a constant expression of type bool.
+
+ ConstraintExpression = ConstraintExpression->IgnoreParenImpCasts();
+
+ if (auto *BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) {
+ if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr)
+ return CheckConstraintExpression(BinOp->getLHS()) &&
+ CheckConstraintExpression(BinOp->getRHS());
+ } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression))
+ return CheckConstraintExpression(C->getSubExpr());
+
+ // An atomic constraint!
+ if (ConstraintExpression->isTypeDependent())
+ return true;
+
+ QualType Type = ConstraintExpression->getType();
+ if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) {
+ Diag(ConstraintExpression->getExprLoc(),
+ diag::err_non_bool_atomic_constraint) << Type
+ << ConstraintExpression->getSourceRange();
+ return false;
+ }
+ return true;
+}
+
+bool
+Sema::CalculateConstraintSatisfaction(ConceptDecl *NamedConcept,
+ MultiLevelTemplateArgumentList &MLTAL,
+ Expr *ConstraintExpr,
+ bool &IsSatisfied) {
+ ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
+
+ if (auto *BO = dyn_cast<BinaryOperator>(ConstraintExpr)) {
+ if (BO->getOpcode() == BO_LAnd) {
+ if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(),
+ IsSatisfied))
+ return true;
+ if (!IsSatisfied)
+ return false;
+ return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(),
+ IsSatisfied);
+ } else if (BO->getOpcode() == BO_LOr) {
+ if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(),
+ IsSatisfied))
+ return true;
+ if (IsSatisfied)
+ return false;
+ return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(),
+ IsSatisfied);
+ }
+ }
+ else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr))
+ return CalculateConstraintSatisfaction(NamedConcept, MLTAL, C->getSubExpr(),
+ IsSatisfied);
+
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ *this, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+ // Atomic constraint - substitute arguments and check satisfaction.
+ ExprResult E;
+ {
+ TemplateDeductionInfo Info(ConstraintExpr->getBeginLoc());
+ InstantiatingTemplate Inst(*this, ConstraintExpr->getBeginLoc(),
+ InstantiatingTemplate::ConstraintSubstitution{},
+ NamedConcept, Info,
+ ConstraintExpr->getSourceRange());
+ if (Inst.isInvalid())
+ return true;
+ // We do not want error diagnostics escaping here.
+ Sema::SFINAETrap Trap(*this);
+
+ E = SubstExpr(ConstraintExpr, MLTAL);
+ if (E.isInvalid() || Trap.hasErrorOccurred()) {
+ // C++2a [temp.constr.atomic]p1
+ // ...If substitution results in an invalid type or expression, the
+ // constraint is not satisfied.
+ IsSatisfied = false;
+ return false;
+ }
+ }
+
+ if (!CheckConstraintExpression(E.get()))
+ return true;
+
+ SmallVector<PartialDiagnosticAt, 2> EvaluationDiags;
+ Expr::EvalResult EvalResult;
+ EvalResult.Diag = &EvaluationDiags;
+ if (!E.get()->EvaluateAsRValue(EvalResult, Context)) {
+ // C++2a [temp.constr.atomic]p1
+ // ...E shall be a constant expression of type bool.
+ Diag(E.get()->getBeginLoc(),
+ diag::err_non_constant_constraint_expression)
+ << E.get()->getSourceRange();
+ for (const PartialDiagnosticAt &PDiag : EvaluationDiags)
+ Diag(PDiag.first, PDiag.second);
+ return true;
+ }
+
+ IsSatisfied = EvalResult.Val.getInt().getBoolValue();
+
+ return false;
+} \ No newline at end of file
diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp
index f0347af6a1bb..fd2fd35921ce 100644
--- a/lib/Sema/SemaCoroutine.cpp
+++ b/lib/Sema/SemaCoroutine.cpp
@@ -83,7 +83,7 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD,
// ref-qualifier or with the & ref-qualifier
// -- "rvalue reference to cv X" for functions declared with the &&
// ref-qualifier
- QualType T = MD->getThisType()->getAs<PointerType>()->getPointeeType();
+ QualType T = MD->getThisType()->castAs<PointerType>()->getPointeeType();
T = FnType->getRefQualifier() == RQ_RValue
? S.Context.getRValueReferenceType(T)
: S.Context.getLValueReferenceType(T, /*SpelledAsLValue*/ true);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index a6c52b7d4b2b..62ec83967bff 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -107,7 +107,7 @@ class TypeNameValidatorCCC final : public CorrectionCandidateCallback {
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<TypeNameValidatorCCC>(*this);
+ return std::make_unique<TypeNameValidatorCCC>(*this);
}
private:
@@ -845,18 +845,18 @@ static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS,
return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T));
}
-Sema::NameClassification
-Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name,
- SourceLocation NameLoc, const Token &NextToken,
- bool IsAddressOfOperand, CorrectionCandidateCallback *CCC) {
+Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS,
+ IdentifierInfo *&Name,
+ SourceLocation NameLoc,
+ const Token &NextToken,
+ CorrectionCandidateCallback *CCC) {
DeclarationNameInfo NameInfo(Name, NameLoc);
ObjCMethodDecl *CurMethod = getCurMethodDecl();
- if (NextToken.is(tok::coloncolon)) {
- NestedNameSpecInfo IdInfo(Name, NameLoc, NextToken.getLocation());
- BuildCXXNestedNameSpecifier(S, IdInfo, false, SS, nullptr, false);
- } else if (getLangOpts().CPlusPlus && SS.isSet() &&
- isCurrentClassName(*Name, S, &SS)) {
+ assert(NextToken.isNot(tok::coloncolon) &&
+ "parse nested name specifiers before calling ClassifyName");
+ if (getLangOpts().CPlusPlus && SS.isSet() &&
+ isCurrentClassName(*Name, S, &SS)) {
// Per [class.qual]p2, this names the constructors of SS, not the
// injected-class-name. We don't have a classification for that.
// There's not much point caching this result, since the parser
@@ -880,9 +880,15 @@ Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name,
// FIXME: This lookup really, really needs to be folded in to the normal
// unqualified lookup mechanism.
if (!SS.isSet() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) {
- ExprResult E = LookupInObjCMethod(Result, S, Name, true);
- if (E.get() || E.isInvalid())
- return E;
+ DeclResult Ivar = LookupIvarInObjCMethod(Result, S, Name);
+ if (Ivar.isInvalid())
+ return NameClassification::Error();
+ if (Ivar.isUsable())
+ return NameClassification::NonType(cast<NamedDecl>(Ivar.get()));
+
+ // We defer builtin creation until after ivar lookup inside ObjC methods.
+ if (Result.empty())
+ LookupBuiltin(Result);
}
bool SecondTry = false;
@@ -897,7 +903,7 @@ Corrected:
// In C++, this is an ADL-only call.
// FIXME: Reference?
if (getLangOpts().CPlusPlus)
- return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true);
+ return NameClassification::UndeclaredNonType();
// C90 6.3.2.2:
// If the expression that precedes the parenthesized argument list in a
@@ -911,11 +917,8 @@ Corrected:
// appeared.
//
// We also allow this in C99 as an extension.
- if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S)) {
- Result.addDecl(D);
- Result.resolveKind();
- return BuildDeclarationNameExpr(SS, Result, /*ADL=*/false);
- }
+ if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S))
+ return NameClassification::NonType(D);
}
if (getLangOpts().CPlusPlus2a && !SS.isSet() && NextToken.is(tok::less)) {
@@ -990,9 +993,12 @@ Corrected:
// reference the ivar.
// FIXME: This is a gross hack.
if (ObjCIvarDecl *Ivar = Result.getAsSingle<ObjCIvarDecl>()) {
- Result.clear();
- ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier()));
- return E;
+ DeclResult R =
+ LookupIvarInObjCMethod(Result, S, Ivar->getIdentifier());
+ if (R.isInvalid())
+ return NameClassification::Error();
+ if (R.isUsable())
+ return NameClassification::NonType(Ivar);
}
goto Corrected;
@@ -1018,9 +1024,7 @@ Corrected:
// perform some heroics to see if we actually have a
// template-argument-list, which would indicate a missing 'template'
// keyword here.
- return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(),
- NameInfo, IsAddressOfOperand,
- /*TemplateArgs=*/nullptr);
+ return NameClassification::DependentNonType();
}
case LookupResult::Found:
@@ -1167,9 +1171,57 @@ Corrected:
return ParsedType::make(T);
}
+ // FIXME: This is context-dependent. We need to defer building the member
+ // expression until the classification is consumed.
if (FirstDecl->isCXXClassMember())
- return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result,
- nullptr, S);
+ return NameClassification::ContextIndependentExpr(
+ BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, nullptr,
+ S));
+
+ // If we already know which single declaration is referenced, just annotate
+ // that declaration directly.
+ bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
+ if (Result.isSingleResult() && !ADL)
+ return NameClassification::NonType(Result.getRepresentativeDecl());
+
+ // Build an UnresolvedLookupExpr. Note that this doesn't depend on the
+ // context in which we performed classification, so it's safe to do now.
+ return NameClassification::ContextIndependentExpr(
+ BuildDeclarationNameExpr(SS, Result, ADL));
+}
+
+ExprResult
+Sema::ActOnNameClassifiedAsUndeclaredNonType(IdentifierInfo *Name,
+ SourceLocation NameLoc) {
+ assert(getLangOpts().CPlusPlus && "ADL-only call in C?");
+ CXXScopeSpec SS;
+ LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
+ return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true);
+}
+
+ExprResult
+Sema::ActOnNameClassifiedAsDependentNonType(const CXXScopeSpec &SS,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ bool IsAddressOfOperand) {
+ DeclarationNameInfo NameInfo(Name, NameLoc);
+ return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(),
+ NameInfo, IsAddressOfOperand,
+ /*TemplateArgs=*/nullptr);
+}
+
+ExprResult Sema::ActOnNameClassifiedAsNonType(Scope *S, const CXXScopeSpec &SS,
+ NamedDecl *Found,
+ SourceLocation NameLoc,
+ const Token &NextToken) {
+ if (getCurMethodDecl() && SS.isEmpty())
+ if (auto *Ivar = dyn_cast<ObjCIvarDecl>(Found->getUnderlyingDecl()))
+ return BuildIvarRefExpr(S, NameLoc, Ivar);
+
+ // Reconstruct the lookup result.
+ LookupResult Result(*this, Found->getDeclName(), NameLoc, LookupOrdinaryName);
+ Result.addDecl(Found);
+ Result.resolveKind();
bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren));
return BuildDeclarationNameExpr(SS, Result, ADL);
@@ -1984,10 +2036,27 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
ASTContext::GetBuiltinTypeError Error;
QualType R = Context.GetBuiltinType(ID, Error);
if (Error) {
- if (ForRedeclaration)
- Diag(Loc, diag::warn_implicit_decl_requires_sysheader)
- << getHeaderName(Context.BuiltinInfo, ID, Error)
+ if (!ForRedeclaration)
+ return nullptr;
+
+ // If we have a builtin without an associated type we should not emit a
+ // warning when we were not able to find a type for it.
+ if (Error == ASTContext::GE_Missing_type)
+ return nullptr;
+
+ // If we could not find a type for setjmp it is because the jmp_buf type was
+ // not defined prior to the setjmp declaration.
+ if (Error == ASTContext::GE_Missing_setjmp) {
+ Diag(Loc, diag::warn_implicit_decl_no_jmp_buf)
<< Context.BuiltinInfo.getName(ID);
+ return nullptr;
+ }
+
+ // Generally, we emit a warning that the declaration requires the
+ // appropriate header.
+ Diag(Loc, diag::warn_implicit_decl_requires_sysheader)
+ << getHeaderName(Context.BuiltinInfo, ID, Error)
+ << Context.BuiltinInfo.getName(ID);
return nullptr;
}
@@ -2155,7 +2224,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
if (!T->isPointerType())
break;
if (!T->isVoidPointerType()) {
- QualType PT = T->getAs<PointerType>()->getPointeeType();
+ QualType PT = T->castAs<PointerType>()->getPointeeType();
if (!PT->isStructureType())
break;
}
@@ -2457,43 +2526,33 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
// previous decl", for example if the attribute needs to be consistent
// between redeclarations, you need to call a custom merge function here.
InheritableAttr *NewAttr = nullptr;
- unsigned AttrSpellingListIndex = Attr->getSpellingListIndex();
if (const auto *AA = dyn_cast<AvailabilityAttr>(Attr))
NewAttr = S.mergeAvailabilityAttr(
- D, AA->getRange(), AA->getPlatform(), AA->isImplicit(),
- AA->getIntroduced(), AA->getDeprecated(), AA->getObsoleted(),
- AA->getUnavailable(), AA->getMessage(), AA->getStrict(),
- AA->getReplacement(), AMK, AA->getPriority(), AttrSpellingListIndex);
+ D, *AA, AA->getPlatform(), AA->isImplicit(), AA->getIntroduced(),
+ AA->getDeprecated(), AA->getObsoleted(), AA->getUnavailable(),
+ AA->getMessage(), AA->getStrict(), AA->getReplacement(), AMK,
+ AA->getPriority());
else if (const auto *VA = dyn_cast<VisibilityAttr>(Attr))
- NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
- AttrSpellingListIndex);
+ NewAttr = S.mergeVisibilityAttr(D, *VA, VA->getVisibility());
else if (const auto *VA = dyn_cast<TypeVisibilityAttr>(Attr))
- NewAttr = S.mergeTypeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
- AttrSpellingListIndex);
+ NewAttr = S.mergeTypeVisibilityAttr(D, *VA, VA->getVisibility());
else if (const auto *ImportA = dyn_cast<DLLImportAttr>(Attr))
- NewAttr = S.mergeDLLImportAttr(D, ImportA->getRange(),
- AttrSpellingListIndex);
+ NewAttr = S.mergeDLLImportAttr(D, *ImportA);
else if (const auto *ExportA = dyn_cast<DLLExportAttr>(Attr))
- NewAttr = S.mergeDLLExportAttr(D, ExportA->getRange(),
- AttrSpellingListIndex);
+ NewAttr = S.mergeDLLExportAttr(D, *ExportA);
else if (const auto *FA = dyn_cast<FormatAttr>(Attr))
- NewAttr = S.mergeFormatAttr(D, FA->getRange(), FA->getType(),
- FA->getFormatIdx(), FA->getFirstArg(),
- AttrSpellingListIndex);
+ NewAttr = S.mergeFormatAttr(D, *FA, FA->getType(), FA->getFormatIdx(),
+ FA->getFirstArg());
else if (const auto *SA = dyn_cast<SectionAttr>(Attr))
- NewAttr = S.mergeSectionAttr(D, SA->getRange(), SA->getName(),
- AttrSpellingListIndex);
+ NewAttr = S.mergeSectionAttr(D, *SA, SA->getName());
else if (const auto *CSA = dyn_cast<CodeSegAttr>(Attr))
- NewAttr = S.mergeCodeSegAttr(D, CSA->getRange(), CSA->getName(),
- AttrSpellingListIndex);
+ NewAttr = S.mergeCodeSegAttr(D, *CSA, CSA->getName());
else if (const auto *IA = dyn_cast<MSInheritanceAttr>(Attr))
- NewAttr = S.mergeMSInheritanceAttr(D, IA->getRange(), IA->getBestCase(),
- AttrSpellingListIndex,
+ NewAttr = S.mergeMSInheritanceAttr(D, *IA, IA->getBestCase(),
IA->getSemanticSpelling());
else if (const auto *AA = dyn_cast<AlwaysInlineAttr>(Attr))
- NewAttr = S.mergeAlwaysInlineAttr(D, AA->getRange(),
- &S.Context.Idents.get(AA->getSpelling()),
- AttrSpellingListIndex);
+ NewAttr = S.mergeAlwaysInlineAttr(D, *AA,
+ &S.Context.Idents.get(AA->getSpelling()));
else if (S.getLangOpts().CUDA && isa<FunctionDecl>(D) &&
(isa<CUDAHostAttr>(Attr) || isa<CUDADeviceAttr>(Attr) ||
isa<CUDAGlobalAttr>(Attr))) {
@@ -2501,9 +2560,9 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
// overloading purposes and must not be merged.
return false;
} else if (const auto *MA = dyn_cast<MinSizeAttr>(Attr))
- NewAttr = S.mergeMinSizeAttr(D, MA->getRange(), AttrSpellingListIndex);
+ NewAttr = S.mergeMinSizeAttr(D, *MA);
else if (const auto *OA = dyn_cast<OptimizeNoneAttr>(Attr))
- NewAttr = S.mergeOptimizeNoneAttr(D, OA->getRange(), AttrSpellingListIndex);
+ NewAttr = S.mergeOptimizeNoneAttr(D, *OA);
else if (const auto *InternalLinkageA = dyn_cast<InternalLinkageAttr>(Attr))
NewAttr = S.mergeInternalLinkageAttr(D, *InternalLinkageA);
else if (const auto *CommonA = dyn_cast<CommonAttr>(Attr))
@@ -2517,8 +2576,7 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
AMK == Sema::AMK_ProtocolImplementation))
NewAttr = nullptr;
else if (const auto *UA = dyn_cast<UuidAttr>(Attr))
- NewAttr = S.mergeUuidAttr(D, UA->getRange(), AttrSpellingListIndex,
- UA->getGuid());
+ NewAttr = S.mergeUuidAttr(D, *UA, UA->getGuid());
else if (const auto *SLHA = dyn_cast<SpeculativeLoadHardeningAttr>(Attr))
NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA);
else if (const auto *SLHA = dyn_cast<NoSpeculativeLoadHardeningAttr>(Attr))
@@ -2635,6 +2693,15 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
--E;
continue;
}
+ } else if (isa<SelectAnyAttr>(NewAttribute) &&
+ cast<VarDecl>(New)->isInline() &&
+ !cast<VarDecl>(New)->isInlineSpecified()) {
+ // Don't warn about applying selectany to implicitly inline variables.
+ // Older compilers and language modes would require the use of selectany
+ // to make such variables inline, and it would have no effect if we
+ // honored it.
+ ++I;
+ continue;
}
S.Diag(NewAttribute->getLocation(),
@@ -2645,6 +2712,60 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
}
}
+static void diagnoseMissingConstinit(Sema &S, const VarDecl *InitDecl,
+ const ConstInitAttr *CIAttr,
+ bool AttrBeforeInit) {
+ SourceLocation InsertLoc = InitDecl->getInnerLocStart();
+
+ // Figure out a good way to write this specifier on the old declaration.
+ // FIXME: We should just use the spelling of CIAttr, but we don't preserve
+ // enough of the attribute list spelling information to extract that without
+ // heroics.
+ std::string SuitableSpelling;
+ if (S.getLangOpts().CPlusPlus2a)
+ SuitableSpelling =
+ S.PP.getLastMacroWithSpelling(InsertLoc, {tok::kw_constinit});
+ if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus11)
+ SuitableSpelling = S.PP.getLastMacroWithSpelling(
+ InsertLoc,
+ {tok::l_square, tok::l_square, S.PP.getIdentifierInfo("clang"),
+ tok::coloncolon,
+ S.PP.getIdentifierInfo("require_constant_initialization"),
+ tok::r_square, tok::r_square});
+ if (SuitableSpelling.empty())
+ SuitableSpelling = S.PP.getLastMacroWithSpelling(
+ InsertLoc,
+ {tok::kw___attribute, tok::l_paren, tok::r_paren,
+ S.PP.getIdentifierInfo("require_constant_initialization"),
+ tok::r_paren, tok::r_paren});
+ if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus2a)
+ SuitableSpelling = "constinit";
+ if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus11)
+ SuitableSpelling = "[[clang::require_constant_initialization]]";
+ if (SuitableSpelling.empty())
+ SuitableSpelling = "__attribute__((require_constant_initialization))";
+ SuitableSpelling += " ";
+
+ if (AttrBeforeInit) {
+ // extern constinit int a;
+ // int a = 0; // error (missing 'constinit'), accepted as extension
+ assert(CIAttr->isConstinit() && "should not diagnose this for attribute");
+ S.Diag(InitDecl->getLocation(), diag::ext_constinit_missing)
+ << InitDecl << FixItHint::CreateInsertion(InsertLoc, SuitableSpelling);
+ S.Diag(CIAttr->getLocation(), diag::note_constinit_specified_here);
+ } else {
+ // int a = 0;
+ // constinit extern int a; // error (missing 'constinit')
+ S.Diag(CIAttr->getLocation(),
+ CIAttr->isConstinit() ? diag::err_constinit_added_too_late
+ : diag::warn_require_const_init_added_too_late)
+ << FixItHint::CreateRemoval(SourceRange(CIAttr->getLocation()));
+ S.Diag(InitDecl->getLocation(), diag::note_constinit_missing_here)
+ << CIAttr->isConstinit()
+ << FixItHint::CreateInsertion(InsertLoc, SuitableSpelling);
+ }
+}
+
/// mergeDeclAttributes - Copy attributes from the Old decl to the New one.
void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
AvailabilityMergeKind AMK) {
@@ -2657,12 +2778,47 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
if (!Old->hasAttrs() && !New->hasAttrs())
return;
+ // [dcl.constinit]p1:
+ // If the [constinit] specifier is applied to any declaration of a
+ // variable, it shall be applied to the initializing declaration.
+ const auto *OldConstInit = Old->getAttr<ConstInitAttr>();
+ const auto *NewConstInit = New->getAttr<ConstInitAttr>();
+ if (bool(OldConstInit) != bool(NewConstInit)) {
+ const auto *OldVD = cast<VarDecl>(Old);
+ auto *NewVD = cast<VarDecl>(New);
+
+ // Find the initializing declaration. Note that we might not have linked
+ // the new declaration into the redeclaration chain yet.
+ const VarDecl *InitDecl = OldVD->getInitializingDeclaration();
+ if (!InitDecl &&
+ (NewVD->hasInit() || NewVD->isThisDeclarationADefinition()))
+ InitDecl = NewVD;
+
+ if (InitDecl == NewVD) {
+ // This is the initializing declaration. If it would inherit 'constinit',
+ // that's ill-formed. (Note that we do not apply this to the attribute
+ // form).
+ if (OldConstInit && OldConstInit->isConstinit())
+ diagnoseMissingConstinit(*this, NewVD, OldConstInit,
+ /*AttrBeforeInit=*/true);
+ } else if (NewConstInit) {
+ // This is the first time we've been told that this declaration should
+ // have a constant initializer. If we already saw the initializing
+ // declaration, this is too late.
+ if (InitDecl && InitDecl != NewVD) {
+ diagnoseMissingConstinit(*this, InitDecl, NewConstInit,
+ /*AttrBeforeInit=*/false);
+ NewVD->dropAttr<ConstInitAttr>();
+ }
+ }
+ }
+
// Attributes declared post-definition are currently ignored.
checkNewAttributesAfterDef(*this, New, Old);
if (AsmLabelAttr *NewA = New->getAttr<AsmLabelAttr>()) {
if (AsmLabelAttr *OldA = Old->getAttr<AsmLabelAttr>()) {
- if (OldA->getLabel() != NewA->getLabel()) {
+ if (!OldA->isEquivalent(NewA)) {
// This redeclaration changes __asm__ label.
Diag(New->getLocation(), diag::err_different_asm_label);
Diag(OldA->getLocation(), diag::note_previous_declaration);
@@ -3458,7 +3614,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
}
}
- if (OldQTypeForComparison == NewQType)
+ // If the function types are compatible, merge the declarations. Ignore the
+ // exception specifier because it was already checked above in
+ // CheckEquivalentExceptionSpec, and we don't want follow-on diagnostics
+ // about incompatible types under -fms-compatibility.
+ if (Context.hasSameFunctionTypeIgnoringExceptionSpec(OldQTypeForComparison,
+ NewQType))
return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld);
// If the types are imprecise (due to dependent constructs in friends or
@@ -4090,11 +4251,11 @@ void Sema::notePreviousDefinition(const NamedDecl *Old, SourceLocation New) {
// Is it the same file and same offset? Provide more information on why
// this leads to a redefinition error.
- bool EmittedDiag = false;
if (FNew == FOld && FNewDecLoc.second == FOldDecLoc.second) {
SourceLocation OldIncLoc = SrcMgr.getIncludeLoc(FOldDecLoc.first);
SourceLocation NewIncLoc = SrcMgr.getIncludeLoc(FNewDecLoc.first);
- EmittedDiag = noteFromModuleOrInclude(Old->getOwningModule(), OldIncLoc);
+ bool EmittedDiag =
+ noteFromModuleOrInclude(Old->getOwningModule(), OldIncLoc);
EmittedDiag |= noteFromModuleOrInclude(getCurrentModule(), NewIncLoc);
// If the header has no guards, emit a note suggesting one.
@@ -4175,9 +4336,11 @@ void Sema::handleTagNumbering(const TagDecl *Tag, Scope *TagScope) {
}
// If this tag isn't a direct child of a class, number it if it is local.
+ MangleNumberingContext *MCtx;
Decl *ManglingContextDecl;
- if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext(
- Tag->getDeclContext(), ManglingContextDecl)) {
+ std::tie(MCtx, ManglingContextDecl) =
+ getCurrentMangleNumberContext(Tag->getDeclContext());
+ if (MCtx) {
Context.setManglingNumber(
Tag, MCtx->getManglingNumber(
Tag, getMSManglingNumber(getLangOpts(), TagScope)));
@@ -4299,13 +4462,13 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
// and definitions of functions and variables.
// C++2a [dcl.constexpr]p1: The consteval specifier shall be applied only to
// the declaration of a function or function template
- bool IsConsteval = DS.getConstexprSpecifier() == CSK_consteval;
if (Tag)
Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag)
- << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType()) << IsConsteval;
+ << GetDiagnosticTypeSpecifierID(DS.getTypeSpecType())
+ << DS.getConstexprSpecifier();
else
Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_wrong_decl_kind)
- << IsConsteval;
+ << DS.getConstexprSpecifier();
// Don't emit warnings after this error.
return TagD;
}
@@ -4497,7 +4660,7 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
TypeSpecType == DeclSpec::TST_enum) {
for (const ParsedAttr &AL : DS.getAttributes())
Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored)
- << AL.getName() << GetDiagnosticTypeSpecifierID(TypeSpecType);
+ << AL << GetDiagnosticTypeSpecifierID(TypeSpecType);
}
}
@@ -4686,12 +4849,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
bool Invalid = false;
if (getLangOpts().CPlusPlus) {
const char *PrevSpec = nullptr;
- unsigned DiagID;
if (Record->isUnion()) {
// C++ [class.union]p6:
// C++17 [class.union.anon]p2:
// Anonymous unions declared in a named namespace or in the
// global namespace shall be declared static.
+ unsigned DiagID;
DeclContext *OwnerScope = Owner->getRedeclContext();
if (DS.getStorageClassSpec() != DeclSpec::SCS_static &&
(OwnerScope->isTranslationUnit() ||
@@ -4913,9 +5076,11 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
if (VarDecl *NewVD = dyn_cast<VarDecl>(Anon)) {
if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) {
+ MangleNumberingContext *MCtx;
Decl *ManglingContextDecl;
- if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext(
- NewVD->getDeclContext(), ManglingContextDecl)) {
+ std::tie(MCtx, ManglingContextDecl) =
+ getCurrentMangleNumberContext(NewVD->getDeclContext());
+ if (MCtx) {
Context.setManglingNumber(
NewVD, MCtx->getManglingNumber(
NewVD, getMSManglingNumber(getLangOpts(), S)));
@@ -5649,8 +5814,8 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
return QualType();
}
- return Context.getConstantArrayType(VLATy->getElementType(),
- Res, ArrayType::Normal, 0);
+ return Context.getConstantArrayType(
+ VLATy->getElementType(), Res, VLATy->getSizeExpr(), ArrayType::Normal, 0);
}
static void
@@ -5760,7 +5925,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
<< getLangOpts().CPlusPlus17;
if (D.getDeclSpec().hasConstexprSpecifier())
Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
- << 1 << (D.getDeclSpec().getConstexprSpecifier() == CSK_consteval);
+ << 1 << D.getDeclSpec().getConstexprSpecifier();
if (D.getName().Kind != UnqualifiedIdKind::IK_Identifier) {
if (D.getName().Kind == UnqualifiedIdKind::IK_DeductionGuideName)
@@ -5842,6 +6007,8 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
if (!Previous.empty()) {
Redeclaration = true;
MergeTypedefNameDecl(S, NewTD, Previous);
+ } else {
+ inferGslPointerAttribute(NewTD);
}
if (ShadowedDecl && !Redeclaration)
@@ -6171,9 +6338,8 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
<< NewDecl;
S.Diag(OldDecl->getLocation(), diag::note_previous_declaration);
NewDecl->dropAttr<DLLImportAttr>();
- NewDecl->addAttr(::new (S.Context) DLLExportAttr(
- NewImportAttr->getRange(), S.Context,
- NewImportAttr->getSpellingListIndex()));
+ NewDecl->addAttr(
+ DLLExportAttr::CreateImplicit(S.Context, NewImportAttr->getRange()));
} else {
S.Diag(NewDecl->getLocation(),
diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
@@ -6658,19 +6824,6 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (TemplateParamLists.size() > VDTemplateParamLists)
NewVD->setTemplateParameterListsInfo(
Context, TemplateParamLists.drop_back(VDTemplateParamLists));
-
- if (D.getDeclSpec().hasConstexprSpecifier()) {
- NewVD->setConstexpr(true);
- // C++1z [dcl.spec.constexpr]p1:
- // A static data member declared with the constexpr specifier is
- // implicitly an inline variable.
- if (NewVD->isStaticDataMember() && getLangOpts().CPlusPlus17)
- NewVD->setImplicitlyInline();
- if (D.getDeclSpec().getConstexprSpecifier() == CSK_consteval)
- Diag(D.getDeclSpec().getConstexprSpecLoc(),
- diag::err_constexpr_wrong_decl_kind)
- << /*consteval*/ 1;
- }
}
if (D.getDeclSpec().isInlineSpecified()) {
@@ -6736,6 +6889,38 @@ NamedDecl *Sema::ActOnVariableDeclarator(
NewVD->setTSCSpec(TSCS);
}
+ switch (D.getDeclSpec().getConstexprSpecifier()) {
+ case CSK_unspecified:
+ break;
+
+ case CSK_consteval:
+ Diag(D.getDeclSpec().getConstexprSpecLoc(),
+ diag::err_constexpr_wrong_decl_kind)
+ << D.getDeclSpec().getConstexprSpecifier();
+ LLVM_FALLTHROUGH;
+
+ case CSK_constexpr:
+ NewVD->setConstexpr(true);
+ // C++1z [dcl.spec.constexpr]p1:
+ // A static data member declared with the constexpr specifier is
+ // implicitly an inline variable.
+ if (NewVD->isStaticDataMember() &&
+ (getLangOpts().CPlusPlus17 ||
+ Context.getTargetInfo().getCXXABI().isMicrosoft()))
+ NewVD->setImplicitlyInline();
+ break;
+
+ case CSK_constinit:
+ if (!NewVD->hasGlobalStorage())
+ Diag(D.getDeclSpec().getConstexprSpecLoc(),
+ diag::err_constinit_local_variable);
+ else
+ NewVD->addAttr(ConstInitAttr::Create(
+ Context, D.getDeclSpec().getConstexprSpecLoc(),
+ AttributeCommonInfo::AS_Keyword, ConstInitAttr::Keyword_constinit));
+ break;
+ }
+
// C99 6.7.4p3
// An inline definition of a function with external linkage shall
// not contain a definition of a modifiable object with static or
@@ -6786,7 +6971,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (EmitTLSUnsupportedError &&
((getLangOpts().CUDA && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) ||
(getLangOpts().OpenMPIsDevice &&
- NewVD->hasAttr<OMPDeclareTargetDeclAttr>())))
+ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(NewVD))))
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
diag::err_thread_unsupported);
// CUDA B.2.5: "__shared__ and __constant__ variables have implied static
@@ -6854,8 +7039,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
}
- NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0),
- Context, Label, 0));
+ NewVD->addAttr(::new (Context) AsmLabelAttr(
+ Context, SE->getStrTokenLoc(0), Label, /*IsLiteralLabel=*/true));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier());
@@ -6961,9 +7146,11 @@ NamedDecl *Sema::ActOnVariableDeclarator(
RegisterLocallyScopedExternCDecl(NewVD, S);
if (getLangOpts().CPlusPlus && NewVD->isStaticLocal()) {
+ MangleNumberingContext *MCtx;
Decl *ManglingContextDecl;
- if (MangleNumberingContext *MCtx = getCurrentMangleNumberContext(
- NewVD->getDeclContext(), ManglingContextDecl)) {
+ std::tie(MCtx, ManglingContextDecl) =
+ getCurrentMangleNumberContext(NewVD->getDeclContext());
+ if (MCtx) {
Context.setManglingNumber(
NewVD, MCtx->getManglingNumber(
NewVD, getMSManglingNumber(getLangOpts(), S)));
@@ -7638,7 +7825,7 @@ struct FindOverriddenMethod {
/// CXXRecordDecl::lookupInBases().
bool operator()(const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
RecordDecl *BaseRecord =
- Specifier->getType()->getAs<RecordType>()->getDecl();
+ Specifier->getType()->castAs<RecordType>()->getDecl();
DeclarationName Name = Method->getDeclName();
@@ -7772,7 +7959,7 @@ class DifferentNameValidatorCCC final : public CorrectionCandidateCallback {
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<DifferentNameValidatorCCC>(*this);
+ return std::make_unique<DifferentNameValidatorCCC>(*this);
}
private:
@@ -7976,7 +8163,7 @@ static StorageClass getFunctionStorageClass(Sema &SemaRef, Declarator &D) {
return SC_None;
}
-static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
+static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
DeclContext *DC, QualType &R,
TypeSourceInfo *TInfo,
StorageClass SC,
@@ -8008,13 +8195,22 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
}
ExplicitSpecifier ExplicitSpecifier = D.getDeclSpec().getExplicitSpecifier();
+
ConstexprSpecKind ConstexprKind = D.getDeclSpec().getConstexprSpecifier();
+ if (ConstexprKind == CSK_constinit) {
+ SemaRef.Diag(D.getDeclSpec().getConstexprSpecLoc(),
+ diag::err_constexpr_wrong_decl_kind)
+ << ConstexprKind;
+ ConstexprKind = CSK_unspecified;
+ D.getMutableDeclSpec().ClearConstexprSpec();
+ }
+
// Check that the return type is not an abstract class type.
// For record types, this is done by the AbstractClassUsageDiagnoser once
// the class has been completely parsed.
if (!DC->isRecord() &&
SemaRef.RequireNonAbstractType(
- D.getIdentifierLoc(), R->getAs<FunctionType>()->getReturnType(),
+ D.getIdentifierLoc(), R->castAs<FunctionType>()->getReturnType(),
diag::err_abstract_type_in_decl, SemaRef.AbstractReturnType))
D.setInvalidType();
@@ -8034,10 +8230,10 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
if (DC->isRecord()) {
R = SemaRef.CheckDestructorDeclarator(D, R, SC);
CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
- CXXDestructorDecl *NewDD =
- CXXDestructorDecl::Create(SemaRef.Context, Record, D.getBeginLoc(),
- NameInfo, R, TInfo, isInline,
- /*isImplicitlyDeclared=*/false);
+ CXXDestructorDecl *NewDD = CXXDestructorDecl::Create(
+ SemaRef.Context, Record, D.getBeginLoc(), NameInfo, R, TInfo,
+ isInline,
+ /*isImplicitlyDeclared=*/false, ConstexprKind);
// If the destructor needs an implicit exception specification, set it
// now. FIXME: It'd be nice to be able to create the right type to start
@@ -8068,6 +8264,9 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
}
SemaRef.CheckConversionDeclarator(D, R, SC);
+ if (D.isInvalidType())
+ return nullptr;
+
IsVirtualOkay = true;
return CXXConversionDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
@@ -8439,7 +8638,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier();
- ConstexprSpecKind ConstexprKind = D.getDeclSpec().getConstexprSpecifier();
isFriend = D.getDeclSpec().isFriendSpecified();
if (isFriend && !isInline && D.isFunctionDefinition()) {
// C++ [class.friend]p5
@@ -8638,7 +8836,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- if (ConstexprKind != CSK_unspecified) {
+ if (ConstexprSpecKind ConstexprKind =
+ D.getDeclSpec().getConstexprSpecifier()) {
// C++11 [dcl.constexpr]p2: constexpr functions and constexpr constructors
// are implicitly inline.
NewFD->setImplicitlyInline();
@@ -8646,9 +8845,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// C++11 [dcl.constexpr]p3: functions declared constexpr are required to
// be either constructors or to return a literal type. Therefore,
// destructors cannot be declared constexpr.
- if (isa<CXXDestructorDecl>(NewFD))
+ if (isa<CXXDestructorDecl>(NewFD) && !getLangOpts().CPlusPlus2a) {
Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor)
- << (ConstexprKind == CSK_consteval);
+ << ConstexprKind;
+ }
}
// If __module_private__ was specified, mark the function accordingly.
@@ -8743,8 +8943,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (Expr *E = (Expr*) D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
- NewFD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), Context,
- SE->getString(), 0));
+ NewFD->addAttr(::new (Context)
+ AsmLabelAttr(Context, SE->getStrTokenLoc(0),
+ SE->getString(), /*IsLiteralLabel=*/true));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier());
@@ -8842,9 +9043,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setParams(Params);
if (D.getDeclSpec().isNoreturnSpecified())
- NewFD->addAttr(
- ::new(Context) C11NoReturnAttr(D.getDeclSpec().getNoreturnSpecLoc(),
- Context, 0));
+ NewFD->addAttr(C11NoReturnAttr::Create(Context,
+ D.getDeclSpec().getNoreturnSpecLoc(),
+ AttributeCommonInfo::AS_Keyword));
// Functions returning a variably modified type violate C99 6.7.5.2p2
// because all functions have linkage.
@@ -8856,19 +9057,18 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Apply an implicit SectionAttr if '#pragma clang section text' is active
if (PragmaClangTextSection.Valid && D.isFunctionDefinition() &&
- !NewFD->hasAttr<SectionAttr>()) {
- NewFD->addAttr(PragmaClangTextSectionAttr::CreateImplicit(Context,
- PragmaClangTextSection.SectionName,
- PragmaClangTextSection.PragmaLocation));
- }
+ !NewFD->hasAttr<SectionAttr>())
+ NewFD->addAttr(PragmaClangTextSectionAttr::CreateImplicit(
+ Context, PragmaClangTextSection.SectionName,
+ PragmaClangTextSection.PragmaLocation, AttributeCommonInfo::AS_Pragma));
// Apply an implicit SectionAttr if #pragma code_seg is active.
if (CodeSegStack.CurrentValue && D.isFunctionDefinition() &&
!NewFD->hasAttr<SectionAttr>()) {
- NewFD->addAttr(
- SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate,
- CodeSegStack.CurrentValue->getString(),
- CodeSegStack.CurrentPragmaLocation));
+ NewFD->addAttr(SectionAttr::CreateImplicit(
+ Context, CodeSegStack.CurrentValue->getString(),
+ CodeSegStack.CurrentPragmaLocation, AttributeCommonInfo::AS_Pragma,
+ SectionAttr::Declspec_allocate));
if (UnifySection(CodeSegStack.CurrentValue->getString(),
ASTContext::PSF_Implicit | ASTContext::PSF_Execute |
ASTContext::PSF_Read,
@@ -8999,7 +9199,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// may end up with different effective targets. Instead, a
// specialization inherits its target attributes from its template
// in the CheckFunctionTemplateSpecialization() call below.
- if (getLangOpts().CUDA & !isFunctionTemplateSpecialization)
+ if (getLangOpts().CUDA && !isFunctionTemplateSpecialization)
maybeAddCUDAHostDeviceAttrs(NewFD, Previous);
// If it's a friend (and only if it's a friend), it's possible
@@ -9404,12 +9604,11 @@ Attr *Sema::getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD,
if (Attr *A = getImplicitCodeSegAttrFromClass(*this, FD))
return A;
if (!FD->hasAttr<SectionAttr>() && IsDefinition &&
- CodeSegStack.CurrentValue) {
- return SectionAttr::CreateImplicit(getASTContext(),
- SectionAttr::Declspec_allocate,
- CodeSegStack.CurrentValue->getString(),
- CodeSegStack.CurrentPragmaLocation);
- }
+ CodeSegStack.CurrentValue)
+ return SectionAttr::CreateImplicit(
+ getASTContext(), CodeSegStack.CurrentValue->getString(),
+ CodeSegStack.CurrentPragmaLocation, AttributeCommonInfo::AS_Pragma,
+ SectionAttr::Declspec_allocate);
return nullptr;
}
@@ -9538,10 +9737,13 @@ static bool HasNonMultiVersionAttributes(const FunctionDecl *FD,
return false;
}
-static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
- const FunctionDecl *NewFD,
- bool CausesMV,
- MultiVersionKind MVType) {
+bool Sema::areMultiversionVariantFunctionsCompatible(
+ const FunctionDecl *OldFD, const FunctionDecl *NewFD,
+ const PartialDiagnostic &NoProtoDiagID,
+ const PartialDiagnosticAt &NoteCausedDiagIDAt,
+ const PartialDiagnosticAt &NoSupportDiagIDAt,
+ const PartialDiagnosticAt &DiffDiagIDAt, bool TemplatesSupported,
+ bool ConstexprSupported, bool CLinkageMayDiffer) {
enum DoesntSupport {
FuncTemplates = 0,
VirtFuncs = 1,
@@ -9559,123 +9761,85 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
ConstexprSpec = 2,
InlineSpec = 3,
StorageClass = 4,
- Linkage = 5
+ Linkage = 5,
};
- bool IsCPUSpecificCPUDispatchMVType =
- MVType == MultiVersionKind::CPUDispatch ||
- MVType == MultiVersionKind::CPUSpecific;
-
if (OldFD && !OldFD->getType()->getAs<FunctionProtoType>()) {
- S.Diag(OldFD->getLocation(), diag::err_multiversion_noproto);
- S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+ Diag(OldFD->getLocation(), NoProtoDiagID);
+ Diag(NoteCausedDiagIDAt.first, NoteCausedDiagIDAt.second);
return true;
}
if (!NewFD->getType()->getAs<FunctionProtoType>())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_noproto);
+ return Diag(NewFD->getLocation(), NoProtoDiagID);
- if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) {
- S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported);
- if (OldFD)
- S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
- return true;
- }
-
- // For now, disallow all other attributes. These should be opt-in, but
- // an analysis of all of them is a future FIXME.
- if (CausesMV && OldFD && HasNonMultiVersionAttributes(OldFD, MVType)) {
- S.Diag(OldFD->getLocation(), diag::err_multiversion_no_other_attrs)
- << IsCPUSpecificCPUDispatchMVType;
- S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
- return true;
- }
-
- if (HasNonMultiVersionAttributes(NewFD, MVType))
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_no_other_attrs)
- << IsCPUSpecificCPUDispatchMVType;
-
- if (NewFD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << FuncTemplates;
+ if (!TemplatesSupported &&
+ NewFD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
+ << FuncTemplates;
if (const auto *NewCXXFD = dyn_cast<CXXMethodDecl>(NewFD)) {
if (NewCXXFD->isVirtual())
- return S.Diag(NewCXXFD->getLocation(),
- diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << VirtFuncs;
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
+ << VirtFuncs;
- if (const auto *NewCXXCtor = dyn_cast<CXXConstructorDecl>(NewFD))
- return S.Diag(NewCXXCtor->getLocation(),
- diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << Constructors;
+ if (isa<CXXConstructorDecl>(NewCXXFD))
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
+ << Constructors;
- if (const auto *NewCXXDtor = dyn_cast<CXXDestructorDecl>(NewFD))
- return S.Diag(NewCXXDtor->getLocation(),
- diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << Destructors;
+ if (isa<CXXDestructorDecl>(NewCXXFD))
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
+ << Destructors;
}
if (NewFD->isDeleted())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << DeletedFuncs;
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
+ << DeletedFuncs;
if (NewFD->isDefaulted())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << DefaultedFuncs;
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
+ << DefaultedFuncs;
- if (NewFD->isConstexpr() && (MVType == MultiVersionKind::CPUDispatch ||
- MVType == MultiVersionKind::CPUSpecific))
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType
+ if (!ConstexprSupported && NewFD->isConstexpr())
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
<< (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs);
- QualType NewQType = S.getASTContext().getCanonicalType(NewFD->getType());
+ QualType NewQType = Context.getCanonicalType(NewFD->getType());
const auto *NewType = cast<FunctionType>(NewQType);
QualType NewReturnType = NewType->getReturnType();
if (NewReturnType->isUndeducedType())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support)
- << IsCPUSpecificCPUDispatchMVType << DeducedReturn;
-
- // Only allow transition to MultiVersion if it hasn't been used.
- if (OldFD && CausesMV && OldFD->isUsed(false))
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_after_used);
+ return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second)
+ << DeducedReturn;
// Ensure the return type is identical.
if (OldFD) {
- QualType OldQType = S.getASTContext().getCanonicalType(OldFD->getType());
+ QualType OldQType = Context.getCanonicalType(OldFD->getType());
const auto *OldType = cast<FunctionType>(OldQType);
FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo();
FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo();
if (OldTypeInfo.getCC() != NewTypeInfo.getCC())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
- << CallingConv;
+ return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << CallingConv;
QualType OldReturnType = OldType->getReturnType();
if (OldReturnType != NewReturnType)
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
- << ReturnType;
+ return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << ReturnType;
if (OldFD->getConstexprKind() != NewFD->getConstexprKind())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
- << ConstexprSpec;
+ return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << ConstexprSpec;
if (OldFD->isInlineSpecified() != NewFD->isInlineSpecified())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
- << InlineSpec;
+ return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << InlineSpec;
if (OldFD->getStorageClass() != NewFD->getStorageClass())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
- << StorageClass;
+ return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << StorageClass;
- if (OldFD->isExternC() != NewFD->isExternC())
- return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff)
- << Linkage;
+ if (!CLinkageMayDiffer && OldFD->isExternC() != NewFD->isExternC())
+ return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << Linkage;
- if (S.CheckEquivalentExceptionSpec(
+ if (CheckEquivalentExceptionSpec(
OldFD->getType()->getAs<FunctionProtoType>(), OldFD->getLocation(),
NewFD->getType()->getAs<FunctionProtoType>(), NewFD->getLocation()))
return true;
@@ -9683,6 +9847,52 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
return false;
}
+static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
+ const FunctionDecl *NewFD,
+ bool CausesMV,
+ MultiVersionKind MVType) {
+ if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) {
+ S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported);
+ if (OldFD)
+ S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
+ return true;
+ }
+
+ bool IsCPUSpecificCPUDispatchMVType =
+ MVType == MultiVersionKind::CPUDispatch ||
+ MVType == MultiVersionKind::CPUSpecific;
+
+ // For now, disallow all other attributes. These should be opt-in, but
+ // an analysis of all of them is a future FIXME.
+ if (CausesMV && OldFD && HasNonMultiVersionAttributes(OldFD, MVType)) {
+ S.Diag(OldFD->getLocation(), diag::err_multiversion_no_other_attrs)
+ << IsCPUSpecificCPUDispatchMVType;
+ S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
+ return true;
+ }
+
+ if (HasNonMultiVersionAttributes(NewFD, MVType))
+ return S.Diag(NewFD->getLocation(), diag::err_multiversion_no_other_attrs)
+ << IsCPUSpecificCPUDispatchMVType;
+
+ // Only allow transition to MultiVersion if it hasn't been used.
+ if (OldFD && CausesMV && OldFD->isUsed(false))
+ return S.Diag(NewFD->getLocation(), diag::err_multiversion_after_used);
+
+ return S.areMultiversionVariantFunctionsCompatible(
+ OldFD, NewFD, S.PDiag(diag::err_multiversion_noproto),
+ PartialDiagnosticAt(NewFD->getLocation(),
+ S.PDiag(diag::note_multiversioning_caused_here)),
+ PartialDiagnosticAt(NewFD->getLocation(),
+ S.PDiag(diag::err_multiversion_doesnt_support)
+ << IsCPUSpecificCPUDispatchMVType),
+ PartialDiagnosticAt(NewFD->getLocation(),
+ S.PDiag(diag::err_multiversion_diff)),
+ /*TemplatesSupported=*/false,
+ /*ConstexprSupported=*/!IsCPUSpecificCPUDispatchMVType,
+ /*CLinkageMayDiffer=*/false);
+}
+
/// Check the validity of a multiversion function declaration that is the
/// first of its kind. Also sets the multiversion'ness' of the function itself.
///
@@ -10130,7 +10340,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
if (!getLangOpts().CPlusPlus14 && MD && MD->isConstexpr() &&
!MD->isStatic() && !isa<CXXConstructorDecl>(MD) &&
- !MD->getMethodQualifiers().hasConst()) {
+ !isa<CXXDestructorDecl>(MD) && !MD->getMethodQualifiers().hasConst()) {
CXXMethodDecl *OldMD = nullptr;
if (OldDecl)
OldMD = dyn_cast_or_null<CXXMethodDecl>(OldDecl->getAsFunction());
@@ -11120,6 +11330,15 @@ void Sema::checkNonTrivialCUnionInInitializer(const Expr *Init,
namespace {
+bool shouldIgnoreForRecordTriviality(const FieldDecl *FD) {
+ // Ignore unavailable fields. A field can be marked as unavailable explicitly
+ // in the source code or implicitly by the compiler if it is in a union
+ // defined in a system header and has non-trivial ObjC ownership
+ // qualifications. We don't want those fields to participate in determining
+ // whether the containing union is non-trivial.
+ return FD->hasAttr<UnavailableAttr>();
+}
+
struct DiagNonTrivalCUnionDefaultInitializeVisitor
: DefaultInitializedTypeVisitor<DiagNonTrivalCUnionDefaultInitializeVisitor,
void> {
@@ -11173,7 +11392,8 @@ struct DiagNonTrivalCUnionDefaultInitializeVisitor
<< 0 << 0 << QT.getUnqualifiedType() << "";
for (const FieldDecl *FD : RD->fields())
- asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
+ if (!shouldIgnoreForRecordTriviality(FD))
+ asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
}
void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {}
@@ -11237,7 +11457,8 @@ struct DiagNonTrivalCUnionDestructedTypeVisitor
<< 0 << 1 << QT.getUnqualifiedType() << "";
for (const FieldDecl *FD : RD->fields())
- asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
+ if (!shouldIgnoreForRecordTriviality(FD))
+ asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
}
void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {}
@@ -11302,7 +11523,8 @@ struct DiagNonTrivalCUnionCopyVisitor
<< 0 << 2 << QT.getUnqualifiedType() << "";
for (const FieldDecl *FD : RD->fields())
- asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
+ if (!shouldIgnoreForRecordTriviality(FD))
+ asDerived().visit(FD->getType(), FD, InNonTrivialUnion);
}
void preVisit(QualType::PrimitiveCopyKind PCK, QualType QT,
@@ -11527,9 +11749,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
// Check for self-references within variable initializers.
// Variables declared within a function/method body (except for references)
// are handled by a dataflow analysis.
- if (!VDecl->hasLocalStorage() || VDecl->getType()->isRecordType() ||
- VDecl->getType()->isReferenceType()) {
- CheckSelfReference(*this, RealDecl, Init, DirectInit);
+ // This is undefined behavior in C++, but valid in C.
+ if (getLangOpts().CPlusPlus) {
+ if (!VDecl->hasLocalStorage() || VDecl->getType()->isRecordType() ||
+ VDecl->getType()->isReferenceType()) {
+ CheckSelfReference(*this, RealDecl, Init, DirectInit);
+ }
}
// If the type changed, it means we had an incomplete type that was
@@ -11853,7 +12078,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
if (Var->isStaticDataMember()) {
// C++1z removes the relevant rule; the in-class declaration is always
// a definition there.
- if (!getLangOpts().CPlusPlus17) {
+ if (!getLangOpts().CPlusPlus17 &&
+ !Context.getTargetInfo().getCXXABI().isMicrosoft()) {
Diag(Var->getLocation(),
diag::err_constexpr_static_mem_var_requires_init)
<< Var->getDeclName();
@@ -12239,11 +12465,11 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
Stack = &DataSegStack;
SectionFlags |= ASTContext::PSF_Write;
}
- if (Stack->CurrentValue && !var->hasAttr<SectionAttr>()) {
+ if (Stack->CurrentValue && !var->hasAttr<SectionAttr>())
var->addAttr(SectionAttr::CreateImplicit(
- Context, SectionAttr::Declspec_allocate,
- Stack->CurrentValue->getString(), Stack->CurrentPragmaLocation));
- }
+ Context, Stack->CurrentValue->getString(),
+ Stack->CurrentPragmaLocation, AttributeCommonInfo::AS_Pragma,
+ SectionAttr::Declspec_allocate));
if (const SectionAttr *SA = var->getAttr<SectionAttr>())
if (UnifySection(SA->getName(), SectionFlags, var))
var->dropAttr<SectionAttr>();
@@ -12253,7 +12479,8 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// attribute.
if (CurInitSeg && var->getInit())
var->addAttr(InitSegAttr::CreateImplicit(Context, CurInitSeg->getString(),
- CurInitSegLoc));
+ CurInitSegLoc,
+ AttributeCommonInfo::AS_Pragma));
}
// All the following checks are C++ only.
@@ -12304,17 +12531,17 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// Don't emit further diagnostics about constexpr globals since they
// were just diagnosed.
- if (!var->isConstexpr() && GlobalStorage &&
- var->hasAttr<RequireConstantInitAttr>()) {
+ if (!var->isConstexpr() && GlobalStorage && var->hasAttr<ConstInitAttr>()) {
// FIXME: Need strict checking in C++03 here.
bool DiagErr = getLangOpts().CPlusPlus11
? !var->checkInitIsICE() : !checkConstInit();
if (DiagErr) {
- auto attr = var->getAttr<RequireConstantInitAttr>();
+ auto *Attr = var->getAttr<ConstInitAttr>();
Diag(var->getLocation(), diag::err_require_constant_init_failed)
<< Init->getSourceRange();
- Diag(attr->getLocation(), diag::note_declared_required_constant_init_here)
- << attr->getRange();
+ Diag(Attr->getLocation(),
+ diag::note_declared_required_constant_init_here)
+ << Attr->getRange() << Attr->isConstinit();
if (getLangOpts().CPlusPlus11) {
APValue Value;
SmallVector<PartialDiagnosticAt, 8> Notes;
@@ -12386,9 +12613,7 @@ void Sema::CheckStaticLocalForDllExport(VarDecl *VD) {
NewAttr->setInherited(true);
VD->addAttr(NewAttr);
} else if (Attr *A = FD->getAttr<DLLExportStaticLocalAttr>()) {
- auto *NewAttr = ::new (getASTContext()) DLLExportAttr(A->getRange(),
- getASTContext(),
- A->getSpellingListIndex());
+ auto *NewAttr = DLLExportAttr::CreateImplicit(getASTContext(), *A);
NewAttr->setInherited(true);
VD->addAttr(NewAttr);
@@ -12398,9 +12623,7 @@ void Sema::CheckStaticLocalForDllExport(VarDecl *VD) {
FD->addAttr(NewAttr);
} else if (Attr *A = FD->getAttr<DLLImportStaticLocalAttr>()) {
- auto *NewAttr = ::new (getASTContext()) DLLImportAttr(A->getRange(),
- getASTContext(),
- A->getSpellingListIndex());
+ auto *NewAttr = DLLImportAttr::CreateImplicit(getASTContext(), *A);
NewAttr->setInherited(true);
VD->addAttr(NewAttr);
}
@@ -12420,17 +12643,25 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) {
if (VD->hasGlobalStorage() && VD->isThisDeclarationADefinition() &&
!inTemplateInstantiation() && !VD->hasAttr<SectionAttr>()) {
if (PragmaClangBSSSection.Valid)
- VD->addAttr(PragmaClangBSSSectionAttr::CreateImplicit(Context,
- PragmaClangBSSSection.SectionName,
- PragmaClangBSSSection.PragmaLocation));
+ VD->addAttr(PragmaClangBSSSectionAttr::CreateImplicit(
+ Context, PragmaClangBSSSection.SectionName,
+ PragmaClangBSSSection.PragmaLocation,
+ AttributeCommonInfo::AS_Pragma));
if (PragmaClangDataSection.Valid)
- VD->addAttr(PragmaClangDataSectionAttr::CreateImplicit(Context,
- PragmaClangDataSection.SectionName,
- PragmaClangDataSection.PragmaLocation));
+ VD->addAttr(PragmaClangDataSectionAttr::CreateImplicit(
+ Context, PragmaClangDataSection.SectionName,
+ PragmaClangDataSection.PragmaLocation,
+ AttributeCommonInfo::AS_Pragma));
if (PragmaClangRodataSection.Valid)
- VD->addAttr(PragmaClangRodataSectionAttr::CreateImplicit(Context,
- PragmaClangRodataSection.SectionName,
- PragmaClangRodataSection.PragmaLocation));
+ VD->addAttr(PragmaClangRodataSectionAttr::CreateImplicit(
+ Context, PragmaClangRodataSection.SectionName,
+ PragmaClangRodataSection.PragmaLocation,
+ AttributeCommonInfo::AS_Pragma));
+ if (PragmaClangRelroSection.Valid)
+ VD->addAttr(PragmaClangRelroSectionAttr::CreateImplicit(
+ Context, PragmaClangRelroSection.SectionName,
+ PragmaClangRelroSection.PragmaLocation,
+ AttributeCommonInfo::AS_Pragma));
}
if (auto *DD = dyn_cast<DecompositionDecl>(ThisDecl)) {
@@ -12726,20 +12957,10 @@ void Sema::ActOnDocumentableDecls(ArrayRef<Decl *> Group) {
}
}
- // See if there are any new comments that are not attached to a decl.
- ArrayRef<RawComment *> Comments = Context.getRawCommentList().getComments();
- if (!Comments.empty() &&
- !Comments.back()->isAttached()) {
- // There is at least one comment that not attached to a decl.
- // Maybe it should be attached to one of these decls?
- //
- // Note that this way we pick up not only comments that precede the
- // declaration, but also comments that *follow* the declaration -- thanks to
- // the lookahead in the lexer: we've consumed the semicolon and looked
- // ahead through comments.
- for (unsigned i = 0, e = Group.size(); i != e; ++i)
- Context.getCommentForDecl(Group[i], &PP);
- }
+ // FIMXE: We assume every Decl in the group is in the same file.
+ // This is false when preprocessor constructs the group from decls in
+ // different files (e. g. macros or #include).
+ Context.attachCommentsToJustParsedDecls(Group, &getPreprocessor());
}
/// Common checks for a parameter-declaration that should apply to both function
@@ -12817,7 +13038,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
<< getLangOpts().CPlusPlus17;
if (DS.hasConstexprSpecifier())
Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr)
- << 0 << (D.getDeclSpec().getConstexprSpecifier() == CSK_consteval);
+ << 0 << D.getDeclSpec().getConstexprSpecifier();
DiagnoseFunctionSpecifiers(DS);
@@ -12977,6 +13198,13 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
Context.getAdjustedParameterType(T),
TSInfo, SC, nullptr);
+ // Make a note if we created a new pack in the scope of a lambda, so that
+ // we know that references to that pack must also be expanded within the
+ // lambda scope.
+ if (New->isParameterPack())
+ if (auto *LSI = getEnclosingLambda())
+ LSI->LocalPacks.push_back(New);
+
if (New->getType().hasNonTrivialToPrimitiveDestructCUnion() ||
New->getType().hasNonTrivialToPrimitiveCopyCUnion())
checkNonTrivialCUnion(New->getType(), New->getLocation(),
@@ -13817,8 +14045,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
}
if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
- (!CheckConstexprFunctionDecl(FD) ||
- !CheckConstexprFunctionBody(FD, Body)))
+ !CheckConstexprFunctionDefinition(FD, CheckConstexprKind::Diagnose))
FD->setInvalidDecl();
if (FD && FD->hasAttr<NakedAttr>()) {
@@ -14577,7 +14804,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
UPPC_FixedUnderlyingType))
EnumUnderlying = Context.IntTy.getTypePtr();
- } else if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ } else if (Context.getTargetInfo().getTriple().isWindowsMSVCEnvironment()) {
// For MSVC ABI compatibility, unfixed enums must use an underlying type
// of 'int'. However, if this is an unfixed forward declaration, don't set
// the underlying type unless the user enables -fms-compatibility. This
@@ -15400,6 +15627,9 @@ CreateNewDecl:
if (PrevDecl)
mergeDeclAttributes(New, PrevDecl);
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(New))
+ inferGslOwnerPointerAttribute(CXXRD);
+
// If there's a #pragma GCC visibility in scope, set the visibility of this
// record.
AddPushedVisibilityAttribute(New);
@@ -15469,8 +15699,9 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD,
return;
if (FinalLoc.isValid())
- Record->addAttr(new (Context)
- FinalAttr(FinalLoc, Context, IsFinalSpelledSealed));
+ Record->addAttr(FinalAttr::Create(
+ Context, FinalLoc, AttributeCommonInfo::AS_Keyword,
+ static_cast<FinalAttr::Spelling>(IsFinalSpelledSealed)));
// C++ [class]p2:
// [...] The class-name is also inserted into the scope of the
@@ -16372,6 +16603,21 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
<< FixItHint::CreateInsertion(FD->getLocation(), "*");
QualType T = Context.getObjCObjectPointerType(FD->getType());
FD->setType(T);
+ } else if (Record && Record->isUnion() &&
+ FD->getType().hasNonTrivialObjCLifetime() &&
+ getSourceManager().isInSystemHeader(FD->getLocation()) &&
+ !getLangOpts().CPlusPlus && !FD->hasAttr<UnavailableAttr>() &&
+ (FD->getType().getObjCLifetime() != Qualifiers::OCL_Strong ||
+ !Context.hasDirectOwnershipQualifier(FD->getType()))) {
+ // For backward compatibility, fields of C unions declared in system
+ // headers that have non-trivial ObjC ownership qualifications are marked
+ // as unavailable unless the qualifier is explicit and __strong. This can
+ // break ABI compatibility between programs compiled with ARC and MRR, but
+ // is a better option than rejecting programs using those unions under
+ // ARC.
+ FD->addAttr(UnavailableAttr::CreateImplicit(
+ Context, "", UnavailableAttr::IR_ARCFieldWithOwnership,
+ FD->getLocation()));
} else if (getLangOpts().ObjC &&
getLangOpts().getGC() != LangOptions::NonGC &&
Record && !Record->hasObjectMember()) {
@@ -16381,7 +16627,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
else if (Context.getAsArrayType(FD->getType())) {
QualType BaseType = Context.getBaseElementType(FD->getType());
if (BaseType->isRecordType() &&
- BaseType->getAs<RecordType>()->getDecl()->hasObjectMember())
+ BaseType->castAs<RecordType>()->getDecl()->hasObjectMember())
Record->setHasObjectMember(true);
else if (BaseType->isObjCObjectPointerType() ||
BaseType.isObjCGCStrong())
@@ -16389,7 +16635,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
}
}
- if (Record && !getLangOpts().CPlusPlus && !FD->hasAttr<UnavailableAttr>()) {
+ if (Record && !getLangOpts().CPlusPlus &&
+ !shouldIgnoreForRecordTriviality(FD)) {
QualType FT = FD->getType();
if (FT.isNonTrivialToPrimitiveDefaultInitialize()) {
Record->setNonTrivialToPrimitiveDefaultInitialize(true);
@@ -16685,8 +16932,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
if (Enum->isDependentType() || Val->isTypeDependent())
EltTy = Context.DependentTy;
else {
- if (getLangOpts().CPlusPlus11 && Enum->isFixed() &&
- !getLangOpts().MSVCCompat) {
+ if (getLangOpts().CPlusPlus11 && Enum->isFixed()) {
// 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.
@@ -16711,15 +16957,19 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// we perform a non-narrowing conversion as part of converted constant
// expression checking.
if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
- if (getLangOpts().MSVCCompat) {
+ if (Context.getTargetInfo()
+ .getTriple()
+ .isWindowsMSVCEnvironment()) {
Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy;
- Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).get();
- } else
+ } else {
Diag(IdLoc, diag::err_enumerator_too_large) << EltTy;
- } else
- Val = ImpCastExprToType(Val, EltTy,
- EltTy->isBooleanType() ?
- CK_IntegralToBoolean : CK_IntegralCast)
+ }
+ }
+
+ // Cast to the underlying type.
+ Val = ImpCastExprToType(Val, EltTy,
+ EltTy->isBooleanType() ? CK_IntegralToBoolean
+ : CK_IntegralCast)
.get();
} else if (getLangOpts().CPlusPlus) {
// C++11 [dcl.enum]p5:
@@ -17047,7 +17297,7 @@ static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements,
continue;
// Create new vector and push values onto it.
- auto Vec = llvm::make_unique<ECDVector>();
+ auto Vec = std::make_unique<ECDVector>();
Vec->push_back(D);
Vec->push_back(ECD);
@@ -17371,8 +17621,10 @@ void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
SourceLocation AliasNameLoc) {
NamedDecl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc,
LookupOrdinaryName);
- AsmLabelAttr *Attr =
- AsmLabelAttr::CreateImplicit(Context, AliasName->getName(), AliasNameLoc);
+ AttributeCommonInfo Info(AliasName, SourceRange(AliasNameLoc),
+ AttributeCommonInfo::AS_Pragma);
+ AsmLabelAttr *Attr = AsmLabelAttr::CreateImplicit(
+ Context, AliasName->getName(), /*LiteralLabel=*/true, Info);
// If a declaration that:
// 1) declares a function or a variable
@@ -17395,7 +17647,7 @@ void Sema::ActOnPragmaWeakID(IdentifierInfo* Name,
Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName);
if (PrevDecl) {
- PrevDecl->addAttr(WeakAttr::CreateImplicit(Context, PragmaLoc));
+ PrevDecl->addAttr(WeakAttr::CreateImplicit(Context, PragmaLoc, AttributeCommonInfo::AS_Pragma));
} else {
(void)WeakUndeclaredIdentifiers.insert(
std::pair<IdentifierInfo*,WeakInfo>
@@ -17425,3 +17677,87 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name,
Decl *Sema::getObjCDeclContext() const {
return (dyn_cast_or_null<ObjCContainerDecl>(CurContext));
}
+
+Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD) {
+ // Templates are emitted when they're instantiated.
+ if (FD->isDependentContext())
+ return FunctionEmissionStatus::TemplateDiscarded;
+
+ FunctionEmissionStatus OMPES = FunctionEmissionStatus::Unknown;
+ if (LangOpts.OpenMPIsDevice) {
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl());
+ if (DevTy.hasValue()) {
+ if (*DevTy == OMPDeclareTargetDeclAttr::DT_Host)
+ OMPES = FunctionEmissionStatus::OMPDiscarded;
+ else if (DeviceKnownEmittedFns.count(FD) > 0)
+ OMPES = FunctionEmissionStatus::Emitted;
+ }
+ } else if (LangOpts.OpenMP) {
+ // In OpenMP 4.5 all the functions are host functions.
+ if (LangOpts.OpenMP <= 45) {
+ OMPES = FunctionEmissionStatus::Emitted;
+ } else {
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl());
+ // In OpenMP 5.0 or above, DevTy may be changed later by
+ // #pragma omp declare target to(*) device_type(*). Therefore DevTy
+ // having no value does not imply host. The emission status will be
+ // checked again at the end of compilation unit.
+ if (DevTy.hasValue()) {
+ if (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) {
+ OMPES = FunctionEmissionStatus::OMPDiscarded;
+ } else if (DeviceKnownEmittedFns.count(FD) > 0) {
+ OMPES = FunctionEmissionStatus::Emitted;
+ }
+ }
+ }
+ }
+ if (OMPES == FunctionEmissionStatus::OMPDiscarded ||
+ (OMPES == FunctionEmissionStatus::Emitted && !LangOpts.CUDA))
+ return OMPES;
+
+ if (LangOpts.CUDA) {
+ // When compiling for device, host functions are never emitted. Similarly,
+ // when compiling for host, device and global functions are never emitted.
+ // (Technically, we do emit a host-side stub for global functions, but this
+ // doesn't count for our purposes here.)
+ Sema::CUDAFunctionTarget T = IdentifyCUDATarget(FD);
+ if (LangOpts.CUDAIsDevice && T == Sema::CFT_Host)
+ return FunctionEmissionStatus::CUDADiscarded;
+ if (!LangOpts.CUDAIsDevice &&
+ (T == Sema::CFT_Device || T == Sema::CFT_Global))
+ return FunctionEmissionStatus::CUDADiscarded;
+
+ // Check whether this function is externally visible -- if so, it's
+ // known-emitted.
+ //
+ // We have to check the GVA linkage of the function's *definition* -- if we
+ // only have a declaration, we don't know whether or not the function will
+ // be emitted, because (say) the definition could include "inline".
+ FunctionDecl *Def = FD->getDefinition();
+
+ if (Def &&
+ !isDiscardableGVALinkage(getASTContext().GetGVALinkageForFunction(Def))
+ && (!LangOpts.OpenMP || OMPES == FunctionEmissionStatus::Emitted))
+ return FunctionEmissionStatus::Emitted;
+ }
+
+ // Otherwise, the function is known-emitted if it's in our set of
+ // known-emitted functions.
+ return (DeviceKnownEmittedFns.count(FD) > 0)
+ ? FunctionEmissionStatus::Emitted
+ : FunctionEmissionStatus::Unknown;
+}
+
+bool Sema::shouldIgnoreInHostDeviceCheck(FunctionDecl *Callee) {
+ // Host-side references to a __global__ function refer to the stub, so the
+ // function itself is never emitted and therefore should not be marked.
+ // If we have host fn calls kernel fn calls host+device, the HD function
+ // does not get instantiated on the host. We model this by omitting at the
+ // call to the kernel from the callgraph. This ensures that, when compiling
+ // for host, only HD functions actually called from the host get marked as
+ // known-emitted.
+ return LangOpts.CUDA && !LangOpts.CUDAIsDevice &&
+ IdentifyCUDATarget(Callee) == CFT_Global;
+}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index ee06f8ae5114..b2be6245a814 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -398,18 +398,11 @@ bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum,
/// Applies the given attribute to the Decl without performing any
/// additional semantic checking.
template <typename AttrType>
-static void handleSimpleAttribute(Sema &S, Decl *D, SourceRange SR,
- unsigned SpellingIndex) {
- D->addAttr(::new (S.Context) AttrType(SR, S.Context, SpellingIndex));
+static void handleSimpleAttribute(Sema &S, Decl *D,
+ const AttributeCommonInfo &CI) {
+ D->addAttr(::new (S.Context) AttrType(S.Context, CI));
}
-template <typename AttrType>
-static void handleSimpleAttribute(Sema &S, Decl *D, const ParsedAttr &AL) {
- handleSimpleAttribute<AttrType>(S, D, AL.getRange(),
- AL.getAttributeSpellingListIndex());
-}
-
-
template <typename... DiagnosticArgs>
static const Sema::SemaDiagnosticBuilder&
appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr) {
@@ -429,28 +422,16 @@ appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr, T &&ExtraArg,
/// Otherwise, emit diagnostic {@code DiagID}, passing in all parameters
/// specified in {@code ExtraArgs}.
template <typename AttrType, typename... DiagnosticArgs>
-static void
-handleSimpleAttributeOrDiagnose(Sema &S, Decl *D, SourceRange SR,
- unsigned SpellingIndex,
- bool PassesCheck,
- unsigned DiagID, DiagnosticArgs&&... ExtraArgs) {
+static void handleSimpleAttributeOrDiagnose(Sema &S, Decl *D,
+ const AttributeCommonInfo &CI,
+ bool PassesCheck, unsigned DiagID,
+ DiagnosticArgs &&... ExtraArgs) {
if (!PassesCheck) {
Sema::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID);
appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...);
return;
}
- handleSimpleAttribute<AttrType>(S, D, SR, SpellingIndex);
-}
-
-template <typename AttrType, typename... DiagnosticArgs>
-static void
-handleSimpleAttributeOrDiagnose(Sema &S, Decl *D, const ParsedAttr &AL,
- bool PassesCheck,
- unsigned DiagID,
- DiagnosticArgs&&... ExtraArgs) {
- return handleSimpleAttributeOrDiagnose<AttrType>(
- S, D, AL.getRange(), AL.getAttributeSpellingListIndex(), PassesCheck,
- DiagID, std::forward<DiagnosticArgs>(ExtraArgs)...);
+ handleSimpleAttribute<AttrType>(S, D, CI);
}
template <typename AttrType>
@@ -566,7 +547,7 @@ static bool checkRecordDeclForAttr(const RecordDecl *RD) {
// If it's type-dependent, we assume it could have the attribute.
if (Ty.isDependentType())
return true;
- return Ty.getAs<RecordType>()->getDecl()->hasAttr<AttrType>();
+ return Ty.castAs<RecordType>()->getDecl()->hasAttr<AttrType>();
},
BPaths, true))
return true;
@@ -745,9 +726,7 @@ static void handlePtGuardedVarAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!threadSafetyCheckIsPointer(S, D, AL))
return;
- D->addAttr(::new (S.Context)
- PtGuardedVarAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) PtGuardedVarAttr(S.Context, AL));
}
static bool checkGuardedByAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
@@ -769,8 +748,7 @@ static void handleGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkGuardedByAttrCommon(S, D, AL, Arg))
return;
- D->addAttr(::new (S.Context) GuardedByAttr(
- AL.getRange(), S.Context, Arg, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) GuardedByAttr(S.Context, AL, Arg));
}
static void handlePtGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -781,8 +759,7 @@ static void handlePtGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!threadSafetyCheckIsPointer(S, D, AL))
return;
- D->addAttr(::new (S.Context) PtGuardedByAttr(
- AL.getRange(), S.Context, Arg, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) PtGuardedByAttr(S.Context, AL, Arg));
}
static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
@@ -811,9 +788,8 @@ static void handleAcquiredAfterAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context) AcquiredAfterAttr(
- AL.getRange(), S.Context, StartArg, Args.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ AcquiredAfterAttr(S.Context, AL, StartArg, Args.size()));
}
static void handleAcquiredBeforeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -822,9 +798,8 @@ static void handleAcquiredBeforeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context) AcquiredBeforeAttr(
- AL.getRange(), S.Context, StartArg, Args.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ AcquiredBeforeAttr(S.Context, AL, StartArg, Args.size()));
}
static bool checkLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
@@ -844,8 +819,7 @@ static void handleAssertSharedLockAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? nullptr : &Args[0];
D->addAttr(::new (S.Context)
- AssertSharedLockAttr(AL.getRange(), S.Context, StartArg, Size,
- AL.getAttributeSpellingListIndex()));
+ AssertSharedLockAttr(S.Context, AL, StartArg, Size));
}
static void handleAssertExclusiveLockAttr(Sema &S, Decl *D,
@@ -856,9 +830,8 @@ static void handleAssertExclusiveLockAttr(Sema &S, Decl *D,
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? nullptr : &Args[0];
- D->addAttr(::new (S.Context) AssertExclusiveLockAttr(
- AL.getRange(), S.Context, StartArg, Size,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ AssertExclusiveLockAttr(S.Context, AL, StartArg, Size));
}
/// Checks to be sure that the given parameter number is in bounds, and
@@ -919,8 +892,7 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
D->addAttr(::new (S.Context)
- AllocSizeAttr(AL.getRange(), S.Context, SizeArgNo, NumberArgNo,
- AL.getAttributeSpellingListIndex()));
+ AllocSizeAttr(S.Context, AL, SizeArgNo, NumberArgNo));
}
static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
@@ -947,8 +919,7 @@ static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D,
return;
D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(
- AL.getRange(), S.Context, AL.getArgAsExpr(0), Args.data(), Args.size(),
- AL.getAttributeSpellingListIndex()));
+ S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size()));
}
static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
@@ -958,8 +929,7 @@ static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
return;
D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(
- AL.getRange(), S.Context, AL.getArgAsExpr(0), Args.data(),
- Args.size(), AL.getAttributeSpellingListIndex()));
+ S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size()));
}
static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -970,9 +940,7 @@ static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (Size == 0)
return;
- D->addAttr(::new (S.Context)
- LockReturnedAttr(AL.getRange(), S.Context, Args[0],
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) LockReturnedAttr(S.Context, AL, Args[0]));
}
static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -988,8 +956,7 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expr **StartArg = &Args[0];
D->addAttr(::new (S.Context)
- LocksExcludedAttr(AL.getRange(), S.Context, StartArg, Size,
- AL.getAttributeSpellingListIndex()));
+ LocksExcludedAttr(S.Context, AL, StartArg, Size));
}
static bool checkFunctionConditionAttr(Sema &S, Decl *D, const ParsedAttr &AL,
@@ -1026,9 +993,7 @@ static void handleEnableIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expr *Cond;
StringRef Msg;
if (checkFunctionConditionAttr(S, D, AL, Cond, Msg))
- D->addAttr(::new (S.Context)
- EnableIfAttr(AL.getRange(), S.Context, Cond, Msg,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) EnableIfAttr(S.Context, AL, Cond, Msg));
}
namespace {
@@ -1100,8 +1065,7 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (const auto *FD = dyn_cast<FunctionDecl>(D))
ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond);
D->addAttr(::new (S.Context) DiagnoseIfAttr(
- AL.getRange(), S.Context, Cond, Msg, DiagType, ArgDependent,
- cast<NamedDecl>(D), AL.getAttributeSpellingListIndex()));
+ S.Context, AL, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D)));
}
static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1133,8 +1097,7 @@ static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context) PassObjectSizeAttr(
- AL.getRange(), S.Context, (int)Type, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) PassObjectSizeAttr(S.Context, AL, (int)Type));
}
static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1154,9 +1117,7 @@ static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- ConsumableAttr(AL.getRange(), S.Context, DefaultState,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ConsumableAttr(S.Context, AL, DefaultState));
}
static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD,
@@ -1207,8 +1168,7 @@ static void handleCallableWhenAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
D->addAttr(::new (S.Context)
- CallableWhenAttr(AL.getRange(), S.Context, States.data(),
- States.size(), AL.getAttributeSpellingListIndex()));
+ CallableWhenAttr(S.Context, AL, States.data(), States.size()));
}
static void handleParamTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1242,9 +1202,7 @@ static void handleParamTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// return;
//}
- D->addAttr(::new (S.Context)
- ParamTypestateAttr(AL.getRange(), S.Context, ParamState,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ParamTypestateAttr(S.Context, AL, ParamState));
}
static void handleReturnTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1289,9 +1247,7 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// return;
//}
- D->addAttr(::new (S.Context)
- ReturnTypestateAttr(AL.getRange(), S.Context, ReturnState,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ReturnTypestateAttr(S.Context, AL, ReturnState));
}
static void handleSetTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1313,9 +1269,7 @@ static void handleSetTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- SetTypestateAttr(AL.getRange(), S.Context, NewState,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) SetTypestateAttr(S.Context, AL, NewState));
}
static void handleTestTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1337,9 +1291,7 @@ static void handleTestTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- TestTypestateAttr(AL.getRange(), S.Context, TestState,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) TestTypestateAttr(S.Context, AL, TestState));
}
static void handleExtVectorTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1349,8 +1301,7 @@ static void handleExtVectorTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (auto *TD = dyn_cast<TagDecl>(D))
- TD->addAttr(::new (S.Context) PackedAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ TD->addAttr(::new (S.Context) PackedAttr(S.Context, AL));
else if (auto *FD = dyn_cast<FieldDecl>(D)) {
bool BitfieldByteAligned = (!FD->getType()->isDependentType() &&
!FD->getType()->isIncompleteType() &&
@@ -1363,15 +1314,13 @@ static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.Diag(AL.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
<< AL << FD->getType();
else
- FD->addAttr(::new (S.Context) PackedAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ FD->addAttr(::new (S.Context) PackedAttr(S.Context, AL));
} else {
// Report warning about changed offset in the newer compiler versions.
if (BitfieldByteAligned)
S.Diag(AL.getLoc(), diag::warn_attribute_packed_for_bitfield);
- FD->addAttr(::new (S.Context) PackedAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ FD->addAttr(::new (S.Context) PackedAttr(S.Context, AL));
}
} else
@@ -1408,9 +1357,7 @@ static void handleIBOutlet(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkIBOutletCommon(S, D, AL))
return;
- D->addAttr(::new (S.Context)
- IBOutletAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) IBOutletAttr(S.Context, AL));
}
static void handleIBOutletCollection(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1453,9 +1400,7 @@ static void handleIBOutletCollection(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- IBOutletCollectionAttr(AL.getRange(), S.Context, QTLoc,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) IBOutletCollectionAttr(S.Context, AL, QTLoc));
}
bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) {
@@ -1538,9 +1483,7 @@ static void handleNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
ParamIdx *Start = NonNullArgs.data();
unsigned Size = NonNullArgs.size();
llvm::array_pod_sort(Start, Start + Size);
- D->addAttr(::new (S.Context)
- NonNullAttr(AL.getRange(), S.Context, Start, Size,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NonNullAttr(S.Context, AL, Start, Size));
}
static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D,
@@ -1560,9 +1503,7 @@ static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D,
D->getSourceRange()))
return;
- D->addAttr(::new (S.Context)
- NonNullAttr(AL.getRange(), S.Context, nullptr, 0,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NonNullAttr(S.Context, AL, nullptr, 0));
}
static void handleReturnsNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1572,9 +1513,7 @@ static void handleReturnsNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
/* isReturnValue */ true))
return;
- D->addAttr(::new (S.Context)
- ReturnsNonNullAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ReturnsNonNullAttr(S.Context, AL));
}
static void handleNoEscapeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1589,33 +1528,30 @@ static void handleNoEscapeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context) NoEscapeAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NoEscapeAttr(S.Context, AL));
}
static void handleAssumeAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expr *E = AL.getArgAsExpr(0),
*OE = AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr;
- S.AddAssumeAlignedAttr(AL.getRange(), D, E, OE,
- AL.getAttributeSpellingListIndex());
+ S.AddAssumeAlignedAttr(D, AL, E, OE);
}
static void handleAllocAlignAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- S.AddAllocAlignAttr(AL.getRange(), D, AL.getArgAsExpr(0),
- AL.getAttributeSpellingListIndex());
+ S.AddAllocAlignAttr(D, AL, AL.getArgAsExpr(0));
}
-void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
- Expr *OE, unsigned SpellingListIndex) {
+void Sema::AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
+ Expr *OE) {
QualType ResultType = getFunctionOrMethodResultType(D);
SourceRange SR = getFunctionOrMethodResultSourceRange(D);
- AssumeAlignedAttr TmpAttr(AttrRange, Context, E, OE, SpellingListIndex);
- SourceLocation AttrLoc = AttrRange.getBegin();
+ AssumeAlignedAttr TmpAttr(Context, CI, E, OE);
+ SourceLocation AttrLoc = TmpAttr.getLocation();
if (!isValidPointerAttrType(ResultType, /* RefOkay */ true)) {
Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only)
- << &TmpAttr << AttrRange << SR;
+ << &TmpAttr << TmpAttr.getRange() << SR;
return;
}
@@ -1652,21 +1588,20 @@ void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
}
}
- D->addAttr(::new (Context)
- AssumeAlignedAttr(AttrRange, Context, E, OE, SpellingListIndex));
+ D->addAttr(::new (Context) AssumeAlignedAttr(Context, CI, E, OE));
}
-void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr,
- unsigned SpellingListIndex) {
+void Sema::AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI,
+ Expr *ParamExpr) {
QualType ResultType = getFunctionOrMethodResultType(D);
- AllocAlignAttr TmpAttr(AttrRange, Context, ParamIdx(), SpellingListIndex);
- SourceLocation AttrLoc = AttrRange.getBegin();
+ AllocAlignAttr TmpAttr(Context, CI, ParamIdx());
+ SourceLocation AttrLoc = CI.getLoc();
if (!ResultType->isDependentType() &&
!isValidPointerAttrType(ResultType, /* RefOkay */ true)) {
Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only)
- << &TmpAttr << AttrRange << getFunctionOrMethodResultSourceRange(D);
+ << &TmpAttr << CI.getRange() << getFunctionOrMethodResultSourceRange(D);
return;
}
@@ -1684,8 +1619,7 @@ void Sema::AddAllocAlignAttr(SourceRange AttrRange, Decl *D, Expr *ParamExpr,
return;
}
- D->addAttr(::new (Context)
- AllocAlignAttr(AttrRange, Context, Idx, SpellingListIndex));
+ D->addAttr(::new (Context) AllocAlignAttr(Context, CI, Idx));
}
/// Normalize the attribute, __foo__ becomes foo.
@@ -1716,8 +1650,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// Figure out our Kind.
OwnershipAttr::OwnershipKind K =
- OwnershipAttr(AL.getLoc(), S.Context, nullptr, nullptr, 0,
- AL.getAttributeSpellingListIndex()).getOwnKind();
+ OwnershipAttr(S.Context, AL, nullptr, nullptr, 0).getOwnKind();
// Check arguments.
switch (K) {
@@ -1799,8 +1732,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
unsigned Size = OwnershipArgs.size();
llvm::array_pod_sort(Start, Start + Size);
D->addAttr(::new (S.Context)
- OwnershipAttr(AL.getLoc(), S.Context, Module, Start, Size,
- AL.getAttributeSpellingListIndex()));
+ OwnershipAttr(S.Context, AL, Module, Start, Size));
}
static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1856,12 +1788,9 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (AL.getNumArgs() && S.checkStringLiteralArgumentAttr(AL, 0, Str))
// GCC will accept anything as the argument of weakref. Should we
// check for an existing decl?
- D->addAttr(::new (S.Context) AliasAttr(AL.getRange(), S.Context, Str,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str));
- D->addAttr(::new (S.Context)
- WeakRefAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) WeakRefAttr(S.Context, AL));
}
static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1876,8 +1805,7 @@ static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context) IFuncAttr(AL.getRange(), S.Context, Str,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) IFuncAttr(S.Context, AL, Str));
}
static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1918,8 +1846,7 @@ static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
ND->markUsed(S.Context);
}
- D->addAttr(::new (S.Context) AliasAttr(AL.getRange(), S.Context, Str,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str));
}
static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -1936,16 +1863,13 @@ static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- TLSModelAttr(AL.getRange(), S.Context, Model,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) TLSModelAttr(S.Context, AL, Model));
}
static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
QualType ResultType = getFunctionOrMethodResultType(D);
if (ResultType->isAnyPointerType() || ResultType->isBlockPointerType()) {
- D->addAttr(::new (S.Context) RestrictAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) RestrictAttr(S.Context, AL));
return;
}
@@ -1996,13 +1920,11 @@ static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
FD->setIsMultiVersion(true);
if (AL.getKind() == ParsedAttr::AT_CPUSpecific)
- D->addAttr(::new (S.Context) CPUSpecificAttr(
- AL.getRange(), S.Context, CPUs.data(), CPUs.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ CPUSpecificAttr(S.Context, AL, CPUs.data(), CPUs.size()));
else
- D->addAttr(::new (S.Context) CPUDispatchAttr(
- AL.getRange(), S.Context, CPUs.data(), CPUs.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ CPUDispatchAttr(S.Context, AL, CPUs.data(), CPUs.size()));
}
static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2031,8 +1953,7 @@ static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
- D->addAttr(::new (S.Context) NakedAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NakedAttr(S.Context, AL));
}
static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) {
@@ -2044,8 +1965,7 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) {
return;
}
- D->addAttr(::new (S.Context) NoReturnAttr(
- Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NoReturnAttr(S.Context, Attrs));
}
static void handleNoCfCheckAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) {
@@ -2091,9 +2011,7 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
- D->addAttr(::new (S.Context)
- AnalyzerNoReturnAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(S.Context, AL));
}
// PS3 PPU-specific.
@@ -2148,8 +2066,7 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
count++;
}
- D->addAttr(::new (S.Context) VecReturnAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) VecReturnAttr(S.Context, AL));
}
static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D,
@@ -2164,9 +2081,7 @@ static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D,
}
}
- D->addAttr(::new (S.Context) CarriesDependencyAttr(
- AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CarriesDependencyAttr(S.Context, AL));
}
static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2177,8 +2092,7 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!S.getLangOpts().CPlusPlus17 && IsCXX17Attr)
S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL;
- D->addAttr(::new (S.Context) UnusedAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL));
}
static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2187,9 +2101,7 @@ static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
return;
- D->addAttr(::new (S.Context)
- ConstructorAttr(AL.getRange(), S.Context, priority,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority));
}
static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2198,9 +2110,7 @@ static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
return;
- D->addAttr(::new (S.Context)
- DestructorAttr(AL.getRange(), S.Context, priority,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority));
}
template <typename AttrTy>
@@ -2210,8 +2120,7 @@ static void handleAttrWithMessage(Sema &S, Decl *D, const ParsedAttr &AL) {
if (AL.getNumArgs() == 1 && !S.checkStringLiteralArgumentAttr(AL, 0, Str))
return;
- D->addAttr(::new (S.Context) AttrTy(AL.getRange(), S.Context, Str,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AttrTy(S.Context, AL, Str));
}
static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D,
@@ -2222,9 +2131,7 @@ static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context)
- ObjCExplicitProtocolImplAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCExplicitProtocolImplAttr(S.Context, AL));
}
static bool checkAvailabilityAttr(Sema &S, SourceRange Range,
@@ -2285,10 +2192,11 @@ static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y,
}
AvailabilityAttr *Sema::mergeAvailabilityAttr(
- NamedDecl *D, SourceRange Range, IdentifierInfo *Platform, bool Implicit,
- VersionTuple Introduced, VersionTuple Deprecated, VersionTuple Obsoleted,
- bool IsUnavailable, StringRef Message, bool IsStrict, StringRef Replacement,
- AvailabilityMergeKind AMK, int Priority, unsigned AttrSpellingListIndex) {
+ NamedDecl *D, const AttributeCommonInfo &CI, IdentifierInfo *Platform,
+ bool Implicit, VersionTuple Introduced, VersionTuple Deprecated,
+ VersionTuple Obsoleted, bool IsUnavailable, StringRef Message,
+ bool IsStrict, StringRef Replacement, AvailabilityMergeKind AMK,
+ int Priority) {
VersionTuple MergedIntroduced = Introduced;
VersionTuple MergedDeprecated = Deprecated;
VersionTuple MergedObsoleted = Obsoleted;
@@ -2379,12 +2287,12 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(
<< (AMK == AMK_Override);
}
if (AMK == AMK_Override)
- Diag(Range.getBegin(), diag::note_overridden_method);
+ Diag(CI.getLoc(), diag::note_overridden_method);
else
- Diag(Range.getBegin(), diag::note_protocol_method);
+ Diag(CI.getLoc(), diag::note_protocol_method);
} else {
Diag(OldAA->getLocation(), diag::warn_mismatched_availability);
- Diag(Range.getBegin(), diag::note_previous_attribute);
+ Diag(CI.getLoc(), diag::note_previous_attribute);
}
Attrs.erase(Attrs.begin() + i);
@@ -2426,13 +2334,12 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(
// Only create a new attribute if !OverrideOrImpl, but we want to do
// the checking.
- if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced,
+ if (!checkAvailabilityAttr(*this, CI.getRange(), Platform, MergedIntroduced,
MergedDeprecated, MergedObsoleted) &&
!OverrideOrImpl) {
- auto *Avail = ::new (Context)
- AvailabilityAttr(Range, Context, Platform, Introduced, Deprecated,
- Obsoleted, IsUnavailable, Message, IsStrict,
- Replacement, Priority, AttrSpellingListIndex);
+ auto *Avail = ::new (Context) AvailabilityAttr(
+ Context, CI, Platform, Introduced, Deprecated, Obsoleted, IsUnavailable,
+ Message, IsStrict, Replacement, Priority);
Avail->setImplicit(Implicit);
return Avail;
}
@@ -2443,7 +2350,6 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkAttributeNumArgs(S, AL, 1))
return;
IdentifierLoc *Platform = AL.getArgAsIdent(0);
- unsigned Index = AL.getAttributeSpellingListIndex();
IdentifierInfo *II = Platform->Ident;
if (AvailabilityAttr::getPrettyPlatformName(II->getName()).empty())
@@ -2479,9 +2385,9 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
? Sema::AP_PragmaClangAttribute
: Sema::AP_Explicit;
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
- ND, AL.getRange(), II, false /*Implicit*/, Introduced.Version,
- Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict,
- Replacement, Sema::AMK_None, PriorityModifier, Index);
+ ND, AL, II, false /*Implicit*/, Introduced.Version, Deprecated.Version,
+ Obsoleted.Version, IsUnavailable, Str, IsStrict, Replacement,
+ Sema::AMK_None, PriorityModifier);
if (NewAttr)
D->addAttr(NewAttr);
@@ -2519,10 +2425,10 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version);
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
- ND, AL.getRange(), NewII, true /*Implicit*/, NewIntroduced,
- NewDeprecated, NewObsoleted, IsUnavailable, Str, IsStrict,
- Replacement, Sema::AMK_None,
- PriorityModifier + Sema::AP_InferredFromOtherPlatform, Index);
+ ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated,
+ NewObsoleted, IsUnavailable, Str, IsStrict, Replacement,
+ Sema::AMK_None,
+ PriorityModifier + Sema::AP_InferredFromOtherPlatform);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -2537,10 +2443,10 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (NewII) {
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
- ND, AL.getRange(), NewII, true /*Implicit*/, Introduced.Version,
+ ND, AL, NewII, true /*Implicit*/, Introduced.Version,
Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict,
Replacement, Sema::AMK_None,
- PriorityModifier + Sema::AP_InferredFromOtherPlatform, Index);
+ PriorityModifier + Sema::AP_InferredFromOtherPlatform);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -2563,38 +2469,34 @@ static void handleExternalSourceSymbolAttr(Sema &S, Decl *D,
bool IsGeneratedDeclaration = AL.getArgAsIdent(2) != nullptr;
D->addAttr(::new (S.Context) ExternalSourceSymbolAttr(
- AL.getRange(), S.Context, Language, DefinedIn, IsGeneratedDeclaration,
- AL.getAttributeSpellingListIndex()));
+ S.Context, AL, Language, DefinedIn, IsGeneratedDeclaration));
}
template <class T>
-static T *mergeVisibilityAttr(Sema &S, Decl *D, SourceRange range,
- typename T::VisibilityType value,
- unsigned attrSpellingListIndex) {
+static T *mergeVisibilityAttr(Sema &S, Decl *D, const AttributeCommonInfo &CI,
+ typename T::VisibilityType value) {
T *existingAttr = D->getAttr<T>();
if (existingAttr) {
typename T::VisibilityType existingValue = existingAttr->getVisibility();
if (existingValue == value)
return nullptr;
S.Diag(existingAttr->getLocation(), diag::err_mismatched_visibility);
- S.Diag(range.getBegin(), diag::note_previous_attribute);
+ S.Diag(CI.getLoc(), diag::note_previous_attribute);
D->dropAttr<T>();
}
- return ::new (S.Context) T(range, S.Context, value, attrSpellingListIndex);
+ return ::new (S.Context) T(S.Context, CI, value);
}
-VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D, SourceRange Range,
- VisibilityAttr::VisibilityType Vis,
- unsigned AttrSpellingListIndex) {
- return ::mergeVisibilityAttr<VisibilityAttr>(*this, D, Range, Vis,
- AttrSpellingListIndex);
+VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D,
+ const AttributeCommonInfo &CI,
+ VisibilityAttr::VisibilityType Vis) {
+ return ::mergeVisibilityAttr<VisibilityAttr>(*this, D, CI, Vis);
}
-TypeVisibilityAttr *Sema::mergeTypeVisibilityAttr(Decl *D, SourceRange Range,
- TypeVisibilityAttr::VisibilityType Vis,
- unsigned AttrSpellingListIndex) {
- return ::mergeVisibilityAttr<TypeVisibilityAttr>(*this, D, Range, Vis,
- AttrSpellingListIndex);
+TypeVisibilityAttr *
+Sema::mergeTypeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI,
+ TypeVisibilityAttr::VisibilityType Vis) {
+ return ::mergeVisibilityAttr<TypeVisibilityAttr>(*this, D, CI, Vis);
}
static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL,
@@ -2636,14 +2538,12 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL,
type = VisibilityAttr::Default;
}
- unsigned Index = AL.getAttributeSpellingListIndex();
Attr *newAttr;
if (isTypeVisibility) {
- newAttr = S.mergeTypeVisibilityAttr(D, AL.getRange(),
- (TypeVisibilityAttr::VisibilityType) type,
- Index);
+ newAttr = S.mergeTypeVisibilityAttr(
+ D, AL, (TypeVisibilityAttr::VisibilityType)type);
} else {
- newAttr = S.mergeVisibilityAttr(D, AL.getRange(), type, Index);
+ newAttr = S.mergeVisibilityAttr(D, AL, type);
}
if (newAttr)
D->addAttr(newAttr);
@@ -2672,8 +2572,7 @@ static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(new (S.Context) ObjCMethodFamilyAttr(
- AL.getRange(), S.Context, F, AL.getAttributeSpellingListIndex()));
+ D->addAttr(new (S.Context) ObjCMethodFamilyAttr(S.Context, AL, F));
}
static void handleObjCNSObject(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2700,9 +2599,7 @@ static void handleObjCNSObject(Sema &S, Decl *D, const ParsedAttr &AL) {
// case.
S.Diag(D->getLocation(), diag::warn_nsobject_attribute);
}
- D->addAttr(::new (S.Context)
- ObjCNSObjectAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCNSObjectAttr(S.Context, AL));
}
static void handleObjCIndependentClass(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2716,9 +2613,7 @@ static void handleObjCIndependentClass(Sema &S, Decl *D, const ParsedAttr &AL) {
S.Diag(D->getLocation(), diag::warn_independentclass_attribute);
return;
}
- D->addAttr(::new (S.Context)
- ObjCIndependentClassAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCIndependentClassAttr(S.Context, AL));
}
static void handleBlocksAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2735,9 +2630,7 @@ static void handleBlocksAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- BlocksAttr(AL.getRange(), S.Context, type,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) BlocksAttr(S.Context, AL, type));
}
static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2808,7 +2701,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
const FunctionType *FT = Ty->isFunctionPointerType()
? D->getFunctionType()
- : Ty->getAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
+ : Ty->castAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
if (!cast<FunctionProtoType>(FT)->isVariadic()) {
int m = Ty->isFunctionPointerType() ? 0 : 1;
S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m;
@@ -2824,14 +2717,13 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
<< AL << ExpectedFunctionMethodOrBlock;
return;
}
- D->addAttr(::new (S.Context)
- SentinelAttr(AL.getRange(), S.Context, sentinel, nullPos,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) SentinelAttr(S.Context, AL, sentinel, nullPos));
}
static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) {
if (D->getFunctionType() &&
- D->getFunctionType()->getReturnType()->isVoidType()) {
+ D->getFunctionType()->getReturnType()->isVoidType() &&
+ !isa<CXXConstructorDecl>(D)) {
S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) << AL << 0;
return;
}
@@ -2841,15 +2733,29 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- // If this is spelled as the standard C++17 attribute, but not in C++17, warn
- // about using it as an extension.
- if (!S.getLangOpts().CPlusPlus17 && AL.isCXX11Attribute() &&
- !AL.getScopeName())
- S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL;
+ StringRef Str;
+ if ((AL.isCXX11Attribute() || AL.isC2xAttribute()) && !AL.getScopeName()) {
+ // If this is spelled as the standard C++17 attribute, but not in C++17,
+ // warn about using it as an extension. If there are attribute arguments,
+ // then claim it's a C++2a extension instead.
+ // FIXME: If WG14 does not seem likely to adopt the same feature, add an
+ // extension warning for C2x mode.
+ const LangOptions &LO = S.getLangOpts();
+ if (AL.getNumArgs() == 1) {
+ if (LO.CPlusPlus && !LO.CPlusPlus2a)
+ S.Diag(AL.getLoc(), diag::ext_cxx2a_attr) << AL;
+
+ // Since this this is spelled [[nodiscard]], get the optional string
+ // literal. If in C++ mode, but not in C++2a mode, diagnose as an
+ // extension.
+ // FIXME: C2x should support this feature as well, even as an extension.
+ if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, nullptr))
+ return;
+ } else if (LO.CPlusPlus && !LO.CPlusPlus17)
+ S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL;
+ }
- D->addAttr(::new (S.Context)
- WarnUnusedResultAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) WarnUnusedResultAttr(S.Context, AL, Str));
}
static void handleWeakImportAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2870,9 +2776,7 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- WeakImportAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) WeakImportAttr(S.Context, AL));
}
// Handles reqd_work_group_size and work_group_size_hint.
@@ -2897,9 +2801,8 @@ static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
Existing->getZDim() == WGSize[2]))
S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
- D->addAttr(::new (S.Context) WorkGroupAttr(AL.getRange(), S.Context,
- WGSize[0], WGSize[1], WGSize[2],
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ WorkGroupAttr(S.Context, AL, WGSize[0], WGSize[1], WGSize[2]));
}
// Handles intel_reqd_sub_group_size.
@@ -2919,9 +2822,8 @@ static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
if (Existing && Existing->getSubGroupSize() != SGSize)
S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
- D->addAttr(::new (S.Context) OpenCLIntelReqdSubGroupSizeAttr(
- AL.getRange(), S.Context, SGSize,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ OpenCLIntelReqdSubGroupSizeAttr(S.Context, AL, SGSize));
}
static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -2937,8 +2839,7 @@ static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() &&
(ParmType->isBooleanType() ||
!ParmType->isIntegralType(S.getASTContext()))) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_vec_type_hint)
- << ParmType;
+ S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) << 3 << AL;
return;
}
@@ -2949,18 +2850,15 @@ static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
- D->addAttr(::new (S.Context) VecTypeHintAttr(AL.getLoc(), S.Context,
- ParmTSI,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) VecTypeHintAttr(S.Context, AL, ParmTSI));
}
-SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
- StringRef Name,
- unsigned AttrSpellingListIndex) {
+SectionAttr *Sema::mergeSectionAttr(Decl *D, const AttributeCommonInfo &CI,
+ StringRef Name) {
// Explicit or partial specializations do not inherit
// the section attribute from the primary template.
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- if (AttrSpellingListIndex == SectionAttr::Declspec_allocate &&
+ if (CI.getAttributeSpellingListIndex() == SectionAttr::Declspec_allocate &&
FD->isFunctionTemplateSpecialization())
return nullptr;
}
@@ -2969,11 +2867,10 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
return nullptr;
Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section)
<< 1 /*section*/;
- Diag(Range.getBegin(), diag::note_previous_attribute);
+ Diag(CI.getLoc(), diag::note_previous_attribute);
return nullptr;
}
- return ::new (Context) SectionAttr(Range, Context, Name,
- AttrSpellingListIndex);
+ return ::new (Context) SectionAttr(Context, CI, Name);
}
bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) {
@@ -3005,8 +2902,7 @@ static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- unsigned Index = AL.getAttributeSpellingListIndex();
- SectionAttr *NewAttr = S.mergeSectionAttr(D, AL.getRange(), Str, Index);
+ SectionAttr *NewAttr = S.mergeSectionAttr(D, AL, Str);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -3026,9 +2922,8 @@ static bool checkCodeSegName(Sema &S, SourceLocation LiteralLoc,
return true;
}
-CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, SourceRange Range,
- StringRef Name,
- unsigned AttrSpellingListIndex) {
+CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, const AttributeCommonInfo &CI,
+ StringRef Name) {
// Explicit or partial specializations do not inherit
// the code_seg attribute from the primary template.
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
@@ -3040,11 +2935,10 @@ CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, SourceRange Range,
return nullptr;
Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section)
<< 0 /*codeseg*/;
- Diag(Range.getBegin(), diag::note_previous_attribute);
+ Diag(CI.getLoc(), diag::note_previous_attribute);
return nullptr;
}
- return ::new (Context) CodeSegAttr(Range, Context, Name,
- AttrSpellingListIndex);
+ return ::new (Context) CodeSegAttr(Context, CI, Name);
}
static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -3064,8 +2958,7 @@ static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
D->dropAttr<CodeSegAttr>();
}
- if (CodeSegAttr *CSA = S.mergeCodeSegAttr(D, AL.getRange(), Str,
- AL.getAttributeSpellingListIndex()))
+ if (CodeSegAttr *CSA = S.mergeCodeSegAttr(D, AL, Str))
D->addAttr(CSA);
}
@@ -3107,9 +3000,7 @@ static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.checkTargetAttr(LiteralLoc, Str))
return;
- unsigned Index = AL.getAttributeSpellingListIndex();
- TargetAttr *NewAttr =
- ::new (S.Context) TargetAttr(AL.getRange(), S.Context, Str, Index);
+ TargetAttr *NewAttr = ::new (S.Context) TargetAttr(S.Context, AL, Str);
D->addAttr(NewAttr);
}
@@ -3127,9 +3018,7 @@ static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- MinVectorWidthAttr(AL.getRange(), S.Context, VecWidth,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) MinVectorWidthAttr(S.Context, AL, VecWidth));
}
static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -3184,9 +3073,7 @@ static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- CleanupAttr(AL.getRange(), S.Context, FD,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD));
}
static void handleEnumExtensibilityAttr(Sema &S, Decl *D,
@@ -3205,9 +3092,8 @@ static void handleEnumExtensibilityAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) EnumExtensibilityAttr(
- AL.getRange(), S.Context, ExtensibilityKind,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ EnumExtensibilityAttr(S.Context, AL, ExtensibilityKind));
}
/// Handle __attribute__((format_arg((idx)))) attribute based on
@@ -3225,7 +3111,7 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (NotNSStringTy &&
!isCFStringType(Ty, S.Context) &&
(!Ty->isPointerType() ||
- !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) {
+ !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) {
S.Diag(AL.getLoc(), diag::err_format_attribute_not)
<< "a string type" << IdxExpr->getSourceRange()
<< getFunctionOrMethodParamRange(D, 0);
@@ -3235,15 +3121,14 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!isNSStringType(Ty, S.Context) &&
!isCFStringType(Ty, S.Context) &&
(!Ty->isPointerType() ||
- !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) {
+ !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) {
S.Diag(AL.getLoc(), diag::err_format_attribute_result_not)
<< (NotNSStringTy ? "string type" : "NSString")
<< IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0);
return;
}
- D->addAttr(::new (S.Context) FormatArgAttr(
- AL.getRange(), S.Context, Idx, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) FormatArgAttr(S.Context, AL, Idx));
}
enum FormatAttrKind {
@@ -3311,15 +3196,12 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
AL.setInvalid();
return;
}
- D->addAttr(::new (S.Context)
- InitPriorityAttr(AL.getRange(), S.Context, prioritynum,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) InitPriorityAttr(S.Context, AL, prioritynum));
}
-FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range,
+FormatAttr *Sema::mergeFormatAttr(Decl *D, const AttributeCommonInfo &CI,
IdentifierInfo *Format, int FormatIdx,
- int FirstArg,
- unsigned AttrSpellingListIndex) {
+ int FirstArg) {
// Check whether we already have an equivalent format attribute.
for (auto *F : D->specific_attrs<FormatAttr>()) {
if (F->getType() == Format &&
@@ -3328,13 +3210,12 @@ FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range,
// If we don't have a valid location for this attribute, adopt the
// location.
if (F->getLocation().isInvalid())
- F->setRange(Range);
+ F->setRange(CI.getRange());
return nullptr;
}
}
- return ::new (Context) FormatAttr(Range, Context, Format, FormatIdx,
- FirstArg, AttrSpellingListIndex);
+ return ::new (Context) FormatAttr(Context, CI, Format, FormatIdx, FirstArg);
}
/// Handle __attribute__((format(type,idx,firstarg))) attributes based on
@@ -3416,7 +3297,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
} else if (!Ty->isPointerType() ||
- !Ty->getAs<PointerType>()->getPointeeType()->isCharType()) {
+ !Ty->castAs<PointerType>()->getPointeeType()->isCharType()) {
S.Diag(AL.getLoc(), diag::err_format_attribute_not)
<< "a string type" << IdxExpr->getSourceRange()
<< getFunctionOrMethodParamRange(D, ArgIdx);
@@ -3454,9 +3335,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- FormatAttr *NewAttr = S.mergeFormatAttr(D, AL.getRange(), II,
- Idx, FirstArg,
- AL.getAttributeSpellingListIndex());
+ FormatAttr *NewAttr = S.mergeFormatAttr(D, AL, II, Idx, FirstArg);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -3597,8 +3476,7 @@ static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
D->addAttr(::new (S.Context) CallbackAttr(
- AL.getRange(), S.Context, EncodingIndices.data(), EncodingIndices.size(),
- AL.getAttributeSpellingListIndex()));
+ S.Context, AL, EncodingIndices.data(), EncodingIndices.size()));
}
static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -3669,9 +3547,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
- RD->addAttr(::new (S.Context)
- TransparentUnionAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ RD->addAttr(::new (S.Context) TransparentUnionAttr(S.Context, AL));
}
static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -3687,20 +3563,16 @@ static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- AnnotateAttr(AL.getRange(), S.Context, Str,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AnnotateAttr(S.Context, AL, Str));
}
static void handleAlignValueAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- S.AddAlignValueAttr(AL.getRange(), D, AL.getArgAsExpr(0),
- AL.getAttributeSpellingListIndex());
+ S.AddAlignValueAttr(D, AL, AL.getArgAsExpr(0));
}
-void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
- unsigned SpellingListIndex) {
- AlignValueAttr TmpAttr(AttrRange, Context, E, SpellingListIndex);
- SourceLocation AttrLoc = AttrRange.getBegin();
+void Sema::AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E) {
+ AlignValueAttr TmpAttr(Context, CI, E);
+ SourceLocation AttrLoc = CI.getLoc();
QualType T;
if (const auto *TD = dyn_cast<TypedefNameDecl>(D))
@@ -3732,14 +3604,12 @@ void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
return;
}
- D->addAttr(::new (Context)
- AlignValueAttr(AttrRange, Context, ICE.get(),
- SpellingListIndex));
+ D->addAttr(::new (Context) AlignValueAttr(Context, CI, ICE.get()));
return;
}
// Save dependent expressions in the AST to be instantiated.
- D->addAttr(::new (Context) AlignValueAttr(TmpAttr));
+ D->addAttr(::new (Context) AlignValueAttr(Context, CI, E));
}
static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -3750,8 +3620,7 @@ static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
if (AL.getNumArgs() == 0) {
- D->addAttr(::new (S.Context) AlignedAttr(AL.getRange(), S.Context,
- true, nullptr, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AlignedAttr(S.Context, AL, true, nullptr));
return;
}
@@ -3765,14 +3634,13 @@ static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!AL.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E))
return;
- S.AddAlignedAttr(AL.getRange(), D, E, AL.getAttributeSpellingListIndex(),
- AL.isPackExpansion());
+ S.AddAlignedAttr(D, AL, E, AL.isPackExpansion());
}
-void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
- unsigned SpellingListIndex, bool IsPackExpansion) {
- AlignedAttr TmpAttr(AttrRange, Context, true, E, SpellingListIndex);
- SourceLocation AttrLoc = AttrRange.getBegin();
+void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
+ bool IsPackExpansion) {
+ AlignedAttr TmpAttr(Context, CI, true, E);
+ SourceLocation AttrLoc = CI.getLoc();
// C++11 alignas(...) and C11 _Alignas(...) have additional requirements.
if (TmpAttr.isAlignas()) {
@@ -3824,7 +3692,7 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
}
// Save dependent expressions in the AST to be instantiated.
- AlignedAttr *AA = ::new (Context) AlignedAttr(TmpAttr);
+ AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, true, E);
AA->setPackExpansion(IsPackExpansion);
D->addAttr(AA);
return;
@@ -3877,18 +3745,16 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
}
}
- AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, true,
- ICE.get(), SpellingListIndex);
+ AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, true, ICE.get());
AA->setPackExpansion(IsPackExpansion);
D->addAttr(AA);
}
-void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS,
- unsigned SpellingListIndex, bool IsPackExpansion) {
+void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI,
+ TypeSourceInfo *TS, bool IsPackExpansion) {
// FIXME: Cache the number on the AL object if non-dependent?
// FIXME: Perform checking of type validity
- AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, false, TS,
- SpellingListIndex);
+ AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, false, TS);
AA->setPackExpansion(IsPackExpansion);
D->addAttr(AA);
}
@@ -4032,14 +3898,14 @@ static void handleModeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
IdentifierInfo *Name = AL.getArgAsIdent(0)->Ident;
- S.AddModeAttr(AL.getRange(), D, Name, AL.getAttributeSpellingListIndex());
+ S.AddModeAttr(D, AL, Name);
}
-void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name,
- unsigned SpellingListIndex, bool InInstantiation) {
+void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI,
+ IdentifierInfo *Name, bool InInstantiation) {
StringRef Str = Name->getName();
normalizeName(Str);
- SourceLocation AttrLoc = AttrRange.getBegin();
+ SourceLocation AttrLoc = CI.getLoc();
unsigned DestWidth = 0;
bool IntegerMode = true;
@@ -4090,8 +3956,7 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name,
OldTy = cast<ValueDecl>(D)->getType();
if (OldTy->isDependentType()) {
- D->addAttr(::new (Context)
- ModeAttr(AttrRange, Context, Name, SpellingListIndex));
+ D->addAttr(::new (Context) ModeAttr(Context, CI, Name));
return;
}
@@ -4106,7 +3971,7 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name,
// type, 'enum { A } __attribute__((mode(V4SI)))' is rejected.
if ((isa<EnumDecl>(D) || OldElemTy->getAs<EnumType>()) &&
VectorSize.getBoolValue()) {
- Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << AttrRange;
+ Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << CI.getRange();
return;
}
bool IntegralOrAnyEnumType =
@@ -4173,21 +4038,18 @@ void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name,
else
cast<ValueDecl>(D)->setType(NewTy);
- D->addAttr(::new (Context)
- ModeAttr(AttrRange, Context, Name, SpellingListIndex));
+ D->addAttr(::new (Context) ModeAttr(Context, CI, Name));
}
static void handleNoDebugAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- D->addAttr(::new (S.Context)
- NoDebugAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NoDebugAttr(S.Context, AL));
}
-AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range,
- IdentifierInfo *Ident,
- unsigned AttrSpellingListIndex) {
+AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D,
+ const AttributeCommonInfo &CI,
+ const IdentifierInfo *Ident) {
if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) {
- Diag(Range.getBegin(), diag::warn_attribute_ignored) << Ident;
+ Diag(CI.getLoc(), diag::warn_attribute_ignored) << Ident;
Diag(Optnone->getLocation(), diag::note_conflicting_attribute);
return nullptr;
}
@@ -4195,24 +4057,21 @@ AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range,
if (D->hasAttr<AlwaysInlineAttr>())
return nullptr;
- return ::new (Context) AlwaysInlineAttr(Range, Context,
- AttrSpellingListIndex);
+ return ::new (Context) AlwaysInlineAttr(Context, CI);
}
CommonAttr *Sema::mergeCommonAttr(Decl *D, const ParsedAttr &AL) {
if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, AL))
return nullptr;
- return ::new (Context)
- CommonAttr(AL.getRange(), Context, AL.getAttributeSpellingListIndex());
+ return ::new (Context) CommonAttr(Context, AL);
}
CommonAttr *Sema::mergeCommonAttr(Decl *D, const CommonAttr &AL) {
if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, AL))
return nullptr;
- return ::new (Context)
- CommonAttr(AL.getRange(), Context, AL.getSpellingListIndex());
+ return ::new (Context) CommonAttr(Context, AL);
}
InternalLinkageAttr *Sema::mergeInternalLinkageAttr(Decl *D,
@@ -4236,8 +4095,7 @@ InternalLinkageAttr *Sema::mergeInternalLinkageAttr(Decl *D,
if (checkAttrMutualExclusion<CommonAttr>(*this, D, AL))
return nullptr;
- return ::new (Context) InternalLinkageAttr(
- AL.getRange(), Context, AL.getAttributeSpellingListIndex());
+ return ::new (Context) InternalLinkageAttr(Context, AL);
}
InternalLinkageAttr *
Sema::mergeInternalLinkageAttr(Decl *D, const InternalLinkageAttr &AL) {
@@ -4260,14 +4118,12 @@ Sema::mergeInternalLinkageAttr(Decl *D, const InternalLinkageAttr &AL) {
if (checkAttrMutualExclusion<CommonAttr>(*this, D, AL))
return nullptr;
- return ::new (Context)
- InternalLinkageAttr(AL.getRange(), Context, AL.getSpellingListIndex());
+ return ::new (Context) InternalLinkageAttr(Context, AL);
}
-MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex) {
+MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI) {
if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) {
- Diag(Range.getBegin(), diag::warn_attribute_ignored) << "'minsize'";
+ Diag(CI.getLoc(), diag::warn_attribute_ignored) << "'minsize'";
Diag(Optnone->getLocation(), diag::note_conflicting_attribute);
return nullptr;
}
@@ -4275,7 +4131,7 @@ MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range,
if (D->hasAttr<MinSizeAttr>())
return nullptr;
- return ::new (Context) MinSizeAttr(Range, Context, AttrSpellingListIndex);
+ return ::new (Context) MinSizeAttr(Context, CI);
}
NoSpeculativeLoadHardeningAttr *Sema::mergeNoSpeculativeLoadHardeningAttr(
@@ -4283,28 +4139,26 @@ NoSpeculativeLoadHardeningAttr *Sema::mergeNoSpeculativeLoadHardeningAttr(
if (checkAttrMutualExclusion<SpeculativeLoadHardeningAttr>(*this, D, AL))
return nullptr;
- return ::new (Context) NoSpeculativeLoadHardeningAttr(
- AL.getRange(), Context, AL.getSpellingListIndex());
+ return ::new (Context) NoSpeculativeLoadHardeningAttr(Context, AL);
}
-OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex) {
+OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D,
+ const AttributeCommonInfo &CI) {
if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) {
Diag(Inline->getLocation(), diag::warn_attribute_ignored) << Inline;
- Diag(Range.getBegin(), diag::note_conflicting_attribute);
+ Diag(CI.getLoc(), diag::note_conflicting_attribute);
D->dropAttr<AlwaysInlineAttr>();
}
if (MinSizeAttr *MinSize = D->getAttr<MinSizeAttr>()) {
Diag(MinSize->getLocation(), diag::warn_attribute_ignored) << MinSize;
- Diag(Range.getBegin(), diag::note_conflicting_attribute);
+ Diag(CI.getLoc(), diag::note_conflicting_attribute);
D->dropAttr<MinSizeAttr>();
}
if (D->hasAttr<OptimizeNoneAttr>())
return nullptr;
- return ::new (Context) OptimizeNoneAttr(Range, Context,
- AttrSpellingListIndex);
+ return ::new (Context) OptimizeNoneAttr(Context, CI);
}
SpeculativeLoadHardeningAttr *Sema::mergeSpeculativeLoadHardeningAttr(
@@ -4312,29 +4166,25 @@ SpeculativeLoadHardeningAttr *Sema::mergeSpeculativeLoadHardeningAttr(
if (checkAttrMutualExclusion<NoSpeculativeLoadHardeningAttr>(*this, D, AL))
return nullptr;
- return ::new (Context) SpeculativeLoadHardeningAttr(
- AL.getRange(), Context, AL.getSpellingListIndex());
+ return ::new (Context) SpeculativeLoadHardeningAttr(Context, AL);
}
static void handleAlwaysInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, AL))
return;
- if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr(
- D, AL.getRange(), AL.getName(),
- AL.getAttributeSpellingListIndex()))
+ if (AlwaysInlineAttr *Inline =
+ S.mergeAlwaysInlineAttr(D, AL, AL.getAttrName()))
D->addAttr(Inline);
}
static void handleMinSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (MinSizeAttr *MinSize = S.mergeMinSizeAttr(
- D, AL.getRange(), AL.getAttributeSpellingListIndex()))
+ if (MinSizeAttr *MinSize = S.mergeMinSizeAttr(D, AL))
D->addAttr(MinSize);
}
static void handleOptimizeNoneAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (OptimizeNoneAttr *Optnone = S.mergeOptimizeNoneAttr(
- D, AL.getRange(), AL.getAttributeSpellingListIndex()))
+ if (OptimizeNoneAttr *Optnone = S.mergeOptimizeNoneAttr(D, AL))
D->addAttr(Optnone);
}
@@ -4346,8 +4196,7 @@ static void handleConstantAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.Diag(AL.getLoc(), diag::err_cuda_nonglobal_constant);
return;
}
- D->addAttr(::new (S.Context) CUDAConstantAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CUDAConstantAttr(S.Context, AL));
}
static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -4365,8 +4214,7 @@ static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.CUDADiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared)
<< S.CurrentCUDATarget())
return;
- D->addAttr(::new (S.Context) CUDASharedAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CUDASharedAttr(S.Context, AL));
}
static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -4375,7 +4223,9 @@ static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
const auto *FD = cast<FunctionDecl>(D);
- if (!FD->getReturnType()->isVoidType()) {
+ if (!FD->getReturnType()->isVoidType() &&
+ !FD->getReturnType()->getAs<AutoType>() &&
+ !FD->getReturnType()->isInstantiationDependentType()) {
SourceRange RTRange = FD->getReturnTypeSourceRange();
S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return)
<< FD->getType()
@@ -4395,9 +4245,7 @@ static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (FD->isInlineSpecified() && !S.getLangOpts().CUDAIsDevice)
S.Diag(FD->getBeginLoc(), diag::warn_kern_is_inline) << FD;
- D->addAttr(::new (S.Context)
- CUDAGlobalAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CUDAGlobalAttr(S.Context, AL));
}
static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -4407,9 +4255,10 @@ static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- GNUInlineAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ if (S.LangOpts.CPlusPlus && Fn->getStorageClass() != SC_Extern)
+ S.Diag(AL.getLoc(), diag::warn_gnu_inline_cplusplus_without_extern);
+
+ D->addAttr(::new (S.Context) GNUInlineAttr(S.Context, AL));
}
static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -4429,53 +4278,34 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
switch (AL.getKind()) {
case ParsedAttr::AT_FastCall:
- D->addAttr(::new (S.Context)
- FastCallAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) FastCallAttr(S.Context, AL));
return;
case ParsedAttr::AT_StdCall:
- D->addAttr(::new (S.Context)
- StdCallAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) StdCallAttr(S.Context, AL));
return;
case ParsedAttr::AT_ThisCall:
- D->addAttr(::new (S.Context)
- ThisCallAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ThisCallAttr(S.Context, AL));
return;
case ParsedAttr::AT_CDecl:
- D->addAttr(::new (S.Context)
- CDeclAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CDeclAttr(S.Context, AL));
return;
case ParsedAttr::AT_Pascal:
- D->addAttr(::new (S.Context)
- PascalAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) PascalAttr(S.Context, AL));
return;
case ParsedAttr::AT_SwiftCall:
- D->addAttr(::new (S.Context)
- SwiftCallAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) SwiftCallAttr(S.Context, AL));
return;
case ParsedAttr::AT_VectorCall:
- D->addAttr(::new (S.Context)
- VectorCallAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) VectorCallAttr(S.Context, AL));
return;
case ParsedAttr::AT_MSABI:
- D->addAttr(::new (S.Context)
- MSABIAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) MSABIAttr(S.Context, AL));
return;
case ParsedAttr::AT_SysVABI:
- D->addAttr(::new (S.Context)
- SysVABIAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) SysVABIAttr(S.Context, AL));
return;
case ParsedAttr::AT_RegCall:
- D->addAttr(::new (S.Context) RegCallAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) RegCallAttr(S.Context, AL));
return;
case ParsedAttr::AT_Pcs: {
PcsAttr::PCSType PCS;
@@ -4490,28 +4320,20 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
llvm_unreachable("unexpected calling convention in pcs attribute");
}
- D->addAttr(::new (S.Context)
- PcsAttr(AL.getRange(), S.Context, PCS,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) PcsAttr(S.Context, AL, PCS));
return;
}
case ParsedAttr::AT_AArch64VectorPcs:
- D->addAttr(::new(S.Context)
- AArch64VectorPcsAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AArch64VectorPcsAttr(S.Context, AL));
return;
case ParsedAttr::AT_IntelOclBicc:
- D->addAttr(::new (S.Context)
- IntelOclBiccAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) IntelOclBiccAttr(S.Context, AL));
return;
case ParsedAttr::AT_PreserveMost:
- D->addAttr(::new (S.Context) PreserveMostAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) PreserveMostAttr(S.Context, AL));
return;
case ParsedAttr::AT_PreserveAll:
- D->addAttr(::new (S.Context) PreserveAllAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) PreserveAllAttr(S.Context, AL));
return;
default:
llvm_unreachable("unexpected attribute kind");
@@ -4533,9 +4355,71 @@ static void handleSuppressAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// clang-tidy knows about available rules.
DiagnosticIdentifiers.push_back(RuleName);
}
- D->addAttr(::new (S.Context) SuppressAttr(
- AL.getRange(), S.Context, DiagnosticIdentifiers.data(),
- DiagnosticIdentifiers.size(), AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ SuppressAttr(S.Context, AL, DiagnosticIdentifiers.data(),
+ DiagnosticIdentifiers.size()));
+}
+
+static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ TypeSourceInfo *DerefTypeLoc = nullptr;
+ QualType ParmType;
+ if (AL.hasParsedType()) {
+ ParmType = S.GetTypeFromParser(AL.getTypeArg(), &DerefTypeLoc);
+
+ unsigned SelectIdx = ~0U;
+ if (ParmType->isVoidType())
+ SelectIdx = 0;
+ else if (ParmType->isReferenceType())
+ SelectIdx = 1;
+ else if (ParmType->isArrayType())
+ SelectIdx = 2;
+
+ if (SelectIdx != ~0U) {
+ S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument)
+ << SelectIdx << AL;
+ return;
+ }
+ }
+
+ // To check if earlier decl attributes do not conflict the newly parsed ones
+ // we always add (and check) the attribute to the cannonical decl.
+ D = D->getCanonicalDecl();
+ if (AL.getKind() == ParsedAttr::AT_Owner) {
+ if (checkAttrMutualExclusion<PointerAttr>(S, D, AL))
+ return;
+ if (const auto *OAttr = D->getAttr<OwnerAttr>()) {
+ const Type *ExistingDerefType = OAttr->getDerefTypeLoc()
+ ? OAttr->getDerefType().getTypePtr()
+ : nullptr;
+ if (ExistingDerefType != ParmType.getTypePtrOrNull()) {
+ S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
+ << AL << OAttr;
+ S.Diag(OAttr->getLocation(), diag::note_conflicting_attribute);
+ }
+ return;
+ }
+ for (Decl *Redecl : D->redecls()) {
+ Redecl->addAttr(::new (S.Context) OwnerAttr(S.Context, AL, DerefTypeLoc));
+ }
+ } else {
+ if (checkAttrMutualExclusion<OwnerAttr>(S, D, AL))
+ return;
+ if (const auto *PAttr = D->getAttr<PointerAttr>()) {
+ const Type *ExistingDerefType = PAttr->getDerefTypeLoc()
+ ? PAttr->getDerefType().getTypePtr()
+ : nullptr;
+ if (ExistingDerefType != ParmType.getTypePtrOrNull()) {
+ S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
+ << AL << PAttr;
+ S.Diag(PAttr->getLocation(), diag::note_conflicting_attribute);
+ }
+ return;
+ }
+ for (Decl *Redecl : D->redecls()) {
+ Redecl->addAttr(::new (S.Context)
+ PointerAttr(S.Context, AL, DerefTypeLoc));
+ }
+ }
}
bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
@@ -4668,6 +4552,11 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
CC = CC_C;
break;
+ case TargetInfo::CCCR_Error:
+ Diag(Attrs.getLoc(), diag::error_cconv_unsupported)
+ << Attrs << (int)CallingConventionIgnoredReason::ForThisTarget;
+ break;
+
case TargetInfo::CCCR_Warning: {
Diag(Attrs.getLoc(), diag::warn_cconv_unsupported)
<< Attrs << (int)CallingConventionIgnoredReason::ForThisTarget;
@@ -4721,21 +4610,15 @@ static bool isValidSwiftErrorResultType(QualType Ty) {
return isValidSwiftContextType(Ty);
}
-static void handleParameterABIAttr(Sema &S, Decl *D, const ParsedAttr &Attrs,
- ParameterABI Abi) {
- S.AddParameterABIAttr(Attrs.getRange(), D, Abi,
- Attrs.getAttributeSpellingListIndex());
-}
-
-void Sema::AddParameterABIAttr(SourceRange range, Decl *D, ParameterABI abi,
- unsigned spellingIndex) {
+void Sema::AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI,
+ ParameterABI abi) {
QualType type = cast<ParmVarDecl>(D)->getType();
if (auto existingAttr = D->getAttr<ParameterABIAttr>()) {
if (existingAttr->getABI() != abi) {
- Diag(range.getBegin(), diag::err_attributes_are_not_compatible)
- << getParameterABISpelling(abi) << existingAttr;
+ Diag(CI.getLoc(), diag::err_attributes_are_not_compatible)
+ << getParameterABISpelling(abi) << existingAttr;
Diag(existingAttr->getLocation(), diag::note_conflicting_attribute);
return;
}
@@ -4747,32 +4630,26 @@ void Sema::AddParameterABIAttr(SourceRange range, Decl *D, ParameterABI abi,
case ParameterABI::SwiftContext:
if (!isValidSwiftContextType(type)) {
- Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type)
- << getParameterABISpelling(abi)
- << /*pointer to pointer */ 0 << type;
+ Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
+ << getParameterABISpelling(abi) << /*pointer to pointer */ 0 << type;
}
- D->addAttr(::new (Context)
- SwiftContextAttr(range, Context, spellingIndex));
+ D->addAttr(::new (Context) SwiftContextAttr(Context, CI));
return;
case ParameterABI::SwiftErrorResult:
if (!isValidSwiftErrorResultType(type)) {
- Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type)
- << getParameterABISpelling(abi)
- << /*pointer to pointer */ 1 << type;
+ Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
+ << getParameterABISpelling(abi) << /*pointer to pointer */ 1 << type;
}
- D->addAttr(::new (Context)
- SwiftErrorResultAttr(range, Context, spellingIndex));
+ D->addAttr(::new (Context) SwiftErrorResultAttr(Context, CI));
return;
case ParameterABI::SwiftIndirectResult:
if (!isValidSwiftIndirectResultType(type)) {
- Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type)
- << getParameterABISpelling(abi)
- << /*pointer*/ 0 << type;
+ Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
+ << getParameterABISpelling(abi) << /*pointer*/ 0 << type;
}
- D->addAttr(::new (Context)
- SwiftIndirectResultAttr(range, Context, spellingIndex));
+ D->addAttr(::new (Context) SwiftIndirectResultAttr(Context, CI));
return;
}
llvm_unreachable("bad parameter ABI attribute");
@@ -4855,10 +4732,9 @@ static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E,
return ValArg.getAs<Expr>();
}
-void Sema::AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads,
- Expr *MinBlocks, unsigned SpellingListIndex) {
- CUDALaunchBoundsAttr TmpAttr(AttrRange, Context, MaxThreads, MinBlocks,
- SpellingListIndex);
+void Sema::AddLaunchBoundsAttr(Decl *D, const AttributeCommonInfo &CI,
+ Expr *MaxThreads, Expr *MinBlocks) {
+ CUDALaunchBoundsAttr TmpAttr(Context, CI, MaxThreads, MinBlocks);
MaxThreads = makeLaunchBoundsArgExpr(*this, MaxThreads, TmpAttr, 0);
if (MaxThreads == nullptr)
return;
@@ -4869,8 +4745,8 @@ void Sema::AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads,
return;
}
- D->addAttr(::new (Context) CUDALaunchBoundsAttr(
- AttrRange, Context, MaxThreads, MinBlocks, SpellingListIndex));
+ D->addAttr(::new (Context)
+ CUDALaunchBoundsAttr(Context, CI, MaxThreads, MinBlocks));
}
static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -4878,9 +4754,8 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
!checkAttributeAtMostNumArgs(S, AL, 2))
return;
- S.AddLaunchBoundsAttr(AL.getRange(), D, AL.getArgAsExpr(0),
- AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr,
- AL.getAttributeSpellingListIndex());
+ S.AddLaunchBoundsAttr(D, AL, AL.getArgAsExpr(0),
+ AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr);
}
static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
@@ -4901,7 +4776,7 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
TypeTagIdx))
return;
- bool IsPointer = AL.getName()->getName() == "pointer_with_type_tag";
+ bool IsPointer = AL.getAttrName()->getName() == "pointer_with_type_tag";
if (IsPointer) {
// Ensure that buffer has a pointer type.
unsigned ArgumentIdxAST = ArgumentIdx.getASTIndex();
@@ -4911,8 +4786,8 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
}
D->addAttr(::new (S.Context) ArgumentWithTypeTagAttr(
- AL.getRange(), S.Context, AL.getArgAsIdent(0)->Ident, ArgumentIdx,
- TypeTagIdx, IsPointer, AL.getAttributeSpellingListIndex()));
+ S.Context, AL, AL.getArgAsIdent(0)->Ident, ArgumentIdx, TypeTagIdx,
+ IsPointer));
}
static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
@@ -4937,12 +4812,9 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
S.GetTypeFromParser(AL.getMatchingCType(), &MatchingCTypeLoc);
assert(MatchingCTypeLoc && "no type source info for attribute argument");
- D->addAttr(::new (S.Context)
- TypeTagForDatatypeAttr(AL.getRange(), S.Context, PointerKind,
- MatchingCTypeLoc,
- AL.getLayoutCompatible(),
- AL.getMustBeNull(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) TypeTagForDatatypeAttr(
+ S.Context, AL, PointerKind, MatchingCTypeLoc, AL.getLayoutCompatible(),
+ AL.getMustBeNull()));
}
static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -4954,9 +4826,8 @@ static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
// ArgCount isn't a parameter index [0;n), it's a count [1;n]
- D->addAttr(::new (S.Context) XRayLogArgsAttr(
- AL.getRange(), S.Context, ArgCount.getSourceIndex(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ XRayLogArgsAttr(S.Context, AL, ArgCount.getSourceIndex()));
}
//===----------------------------------------------------------------------===//
@@ -4983,20 +4854,20 @@ static bool isValidSubjectOfOSAttribute(QualType QT) {
return !PT.isNull() && PT->getAsCXXRecordDecl() != nullptr;
}
-void Sema::AddXConsumedAttr(Decl *D, SourceRange SR, unsigned SpellingIndex,
+void Sema::AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI,
RetainOwnershipKind K,
bool IsTemplateInstantiation) {
ValueDecl *VD = cast<ValueDecl>(D);
switch (K) {
case RetainOwnershipKind::OS:
handleSimpleAttributeOrDiagnose<OSConsumedAttr>(
- *this, VD, SR, SpellingIndex, isValidSubjectOfOSAttribute(VD->getType()),
+ *this, VD, CI, isValidSubjectOfOSAttribute(VD->getType()),
diag::warn_ns_attribute_wrong_parameter_type,
- /*ExtraArgs=*/SR, "os_consumed", /*pointers*/ 1);
+ /*ExtraArgs=*/CI.getRange(), "os_consumed", /*pointers*/ 1);
return;
case RetainOwnershipKind::NS:
handleSimpleAttributeOrDiagnose<NSConsumedAttr>(
- *this, VD, SR, SpellingIndex, isValidSubjectOfNSAttribute(VD->getType()),
+ *this, VD, CI, isValidSubjectOfNSAttribute(VD->getType()),
// These attributes are normally just advisory, but in ARC, ns_consumed
// is significant. Allow non-dependent code to contain inappropriate
@@ -5005,14 +4876,13 @@ void Sema::AddXConsumedAttr(Decl *D, SourceRange SR, unsigned SpellingIndex,
((IsTemplateInstantiation && getLangOpts().ObjCAutoRefCount)
? diag::err_ns_attribute_wrong_parameter_type
: diag::warn_ns_attribute_wrong_parameter_type),
- /*ExtraArgs=*/SR, "ns_consumed", /*objc pointers*/ 0);
+ /*ExtraArgs=*/CI.getRange(), "ns_consumed", /*objc pointers*/ 0);
return;
case RetainOwnershipKind::CF:
handleSimpleAttributeOrDiagnose<CFConsumedAttr>(
- *this, VD, SR, SpellingIndex,
- isValidSubjectOfCFAttribute(VD->getType()),
+ *this, VD, CI, isValidSubjectOfCFAttribute(VD->getType()),
diag::warn_ns_attribute_wrong_parameter_type,
- /*ExtraArgs=*/SR, "cf_consumed", /*pointers*/1);
+ /*ExtraArgs=*/CI.getRange(), "cf_consumed", /*pointers*/ 1);
return;
}
}
@@ -5215,8 +5085,7 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr(
- Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr(S.Context, Attrs));
}
static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
@@ -5236,8 +5105,7 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(
- Attrs.getRange(), S.Context, Attrs.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs));
}
static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5263,9 +5131,7 @@ static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
- D->addAttr(::new (S.Context)
- ObjCBridgeAttr(AL.getRange(), S.Context, Parm->Ident,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCBridgeAttr(S.Context, AL, Parm->Ident));
}
static void handleObjCBridgeMutableAttr(Sema &S, Decl *D,
@@ -5278,8 +5144,7 @@ static void handleObjCBridgeMutableAttr(Sema &S, Decl *D,
}
D->addAttr(::new (S.Context)
- ObjCBridgeMutableAttr(AL.getRange(), S.Context, Parm->Ident,
- AL.getAttributeSpellingListIndex()));
+ ObjCBridgeMutableAttr(S.Context, AL, Parm->Ident));
}
static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D,
@@ -5294,10 +5159,8 @@ static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D,
AL.getArgAsIdent(1) ? AL.getArgAsIdent(1)->Ident : nullptr;
IdentifierInfo *InstanceMethod =
AL.getArgAsIdent(2) ? AL.getArgAsIdent(2)->Ident : nullptr;
- D->addAttr(::new (S.Context)
- ObjCBridgeRelatedAttr(AL.getRange(), S.Context, RelatedClass,
- ClassMethod, InstanceMethod,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCBridgeRelatedAttr(
+ S.Context, AL, RelatedClass, ClassMethod, InstanceMethod));
}
static void handleObjCDesignatedInitializer(Sema &S, Decl *D,
@@ -5323,9 +5186,7 @@ static void handleObjCDesignatedInitializer(Sema &S, Decl *D,
return;
IFace->setHasDesignatedInitializers();
- D->addAttr(::new (S.Context)
- ObjCDesignatedInitializerAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCDesignatedInitializerAttr(S.Context, AL));
}
static void handleObjCRuntimeName(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5333,9 +5194,7 @@ static void handleObjCRuntimeName(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!S.checkStringLiteralArgumentAttr(AL, 0, MetaDataName))
return;
D->addAttr(::new (S.Context)
- ObjCRuntimeNameAttr(AL.getRange(), S.Context,
- MetaDataName,
- AL.getAttributeSpellingListIndex()));
+ ObjCRuntimeNameAttr(S.Context, AL, MetaDataName));
}
// When a user wants to use objc_boxable with a union or struct
@@ -5352,9 +5211,8 @@ static void handleObjCBoxable(Sema &S, Decl *D, const ParsedAttr &AL) {
}
if (RD) {
- ObjCBoxableAttr *BoxableAttr = ::new (S.Context)
- ObjCBoxableAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex());
+ ObjCBoxableAttr *BoxableAttr =
+ ::new (S.Context) ObjCBoxableAttr(S.Context, AL);
RD->addAttr(BoxableAttr);
if (notify) {
// we need to notify ASTReader/ASTWriter about
@@ -5408,26 +5266,24 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
break;
}
- D->addAttr(::new (S.Context)
- ObjCPreciseLifetimeAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ObjCPreciseLifetimeAttr(S.Context, AL));
}
//===----------------------------------------------------------------------===//
// Microsoft specific attribute handlers.
//===----------------------------------------------------------------------===//
-UuidAttr *Sema::mergeUuidAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex, StringRef Uuid) {
+UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI,
+ StringRef Uuid) {
if (const auto *UA = D->getAttr<UuidAttr>()) {
if (UA->getGuid().equals_lower(Uuid))
return nullptr;
Diag(UA->getLocation(), diag::err_mismatched_uuid);
- Diag(Range.getBegin(), diag::note_previous_uuid);
+ Diag(CI.getLoc(), diag::note_previous_uuid);
D->dropAttr<UuidAttr>();
}
- return ::new (Context) UuidAttr(Range, Context, Uuid, AttrSpellingListIndex);
+ return ::new (Context) UuidAttr(Context, CI, Uuid);
}
static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5474,8 +5330,7 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling.
S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated);
- UuidAttr *UA = S.mergeUuidAttr(D, AL.getRange(),
- AL.getAttributeSpellingListIndex(), StrRef);
+ UuidAttr *UA = S.mergeUuidAttr(D, AL, StrRef);
if (UA)
D->addAttr(UA);
}
@@ -5487,8 +5342,7 @@ static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
MSInheritanceAttr *IA = S.mergeMSInheritanceAttr(
- D, AL.getRange(), /*BestCase=*/true,
- AL.getAttributeSpellingListIndex(),
+ D, AL, /*BestCase=*/true,
(MSInheritanceAttr::Spelling)AL.getSemanticSpelling());
if (IA) {
D->addAttr(IA);
@@ -5510,8 +5364,7 @@ static void handleDeclspecThreadAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
S.Diag(AL.getLoc(), diag::err_thread_non_global) << "__declspec(thread)";
return;
}
- D->addAttr(::new (S.Context) ThreadAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ThreadAttr(S.Context, AL));
}
static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5542,8 +5395,7 @@ static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end());
D->addAttr(::new (S.Context)
- AbiTagAttr(AL.getRange(), S.Context, Tags.data(), Tags.size(),
- AL.getAttributeSpellingListIndex()));
+ AbiTagAttr(S.Context, AL, Tags.data(), Tags.size()));
}
static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5568,9 +5420,7 @@ static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- unsigned Index = AL.getAttributeSpellingListIndex();
- D->addAttr(::new (S.Context)
- ARMInterruptAttr(AL.getLoc(), S.Context, Kind, Index));
+ D->addAttr(::new (S.Context) ARMInterruptAttr(S.Context, AL, Kind));
}
static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5621,9 +5471,7 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context)
- MSP430InterruptAttr(AL.getLoc(), S.Context, Num,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) MSP430InterruptAttr(S.Context, AL, Num));
D->addAttr(UsedAttr::CreateImplicit(S.Context));
}
@@ -5679,8 +5527,7 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
}
- D->addAttr(::new (S.Context) MipsInterruptAttr(
- AL.getLoc(), S.Context, Kind, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) MipsInterruptAttr(S.Context, AL, Kind));
}
static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5743,8 +5590,7 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
<< 3 << S.Context.getIntTypeForBitwidth(TypeSize, /*Signed=*/false);
return;
}
- D->addAttr(::new (S.Context) AnyX86InterruptAttr(
- AL.getLoc(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AnyX86InterruptAttr(S.Context, AL));
D->addAttr(UsedAttr::CreateImplicit(S.Context));
}
@@ -5792,9 +5638,8 @@ static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
return;
- FD->addAttr(::new (S.Context) WebAssemblyImportModuleAttr(
- AL.getRange(), S.Context, Str,
- AL.getAttributeSpellingListIndex()));
+ FD->addAttr(::new (S.Context)
+ WebAssemblyImportModuleAttr(S.Context, AL, Str));
}
static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5815,9 +5660,7 @@ static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &
if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
return;
- FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(
- AL.getRange(), S.Context, Str,
- AL.getAttributeSpellingListIndex()));
+ FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(S.Context, AL, Str));
}
static void handleRISCVInterruptAttr(Sema &S, Decl *D,
@@ -5875,8 +5718,7 @@ static void handleRISCVInterruptAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) RISCVInterruptAttr(
- AL.getLoc(), S.Context, Kind, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) RISCVInterruptAttr(S.Context, AL, Kind));
}
static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -5936,17 +5778,16 @@ checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr,
return false;
}
-void Sema::addAMDGPUFlatWorkGroupSizeAttr(SourceRange AttrRange, Decl *D,
- Expr *MinExpr, Expr *MaxExpr,
- unsigned SpellingListIndex) {
- AMDGPUFlatWorkGroupSizeAttr TmpAttr(AttrRange, Context, MinExpr, MaxExpr,
- SpellingListIndex);
+void Sema::addAMDGPUFlatWorkGroupSizeAttr(Decl *D,
+ const AttributeCommonInfo &CI,
+ Expr *MinExpr, Expr *MaxExpr) {
+ AMDGPUFlatWorkGroupSizeAttr TmpAttr(Context, CI, MinExpr, MaxExpr);
if (checkAMDGPUFlatWorkGroupSizeArguments(*this, MinExpr, MaxExpr, TmpAttr))
return;
- D->addAttr(::new (Context) AMDGPUFlatWorkGroupSizeAttr(
- AttrRange, Context, MinExpr, MaxExpr, SpellingListIndex));
+ D->addAttr(::new (Context)
+ AMDGPUFlatWorkGroupSizeAttr(Context, CI, MinExpr, MaxExpr));
}
static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D,
@@ -5954,8 +5795,7 @@ static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D,
Expr *MinExpr = AL.getArgAsExpr(0);
Expr *MaxExpr = AL.getArgAsExpr(1);
- S.addAMDGPUFlatWorkGroupSizeAttr(AL.getRange(), D, MinExpr, MaxExpr,
- AL.getAttributeSpellingListIndex());
+ S.addAMDGPUFlatWorkGroupSizeAttr(D, AL, MinExpr, MaxExpr);
}
static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr,
@@ -5992,17 +5832,15 @@ static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr,
return false;
}
-void Sema::addAMDGPUWavesPerEUAttr(SourceRange AttrRange, Decl *D,
- Expr *MinExpr, Expr *MaxExpr,
- unsigned SpellingListIndex) {
- AMDGPUWavesPerEUAttr TmpAttr(AttrRange, Context, MinExpr, MaxExpr,
- SpellingListIndex);
+void Sema::addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI,
+ Expr *MinExpr, Expr *MaxExpr) {
+ AMDGPUWavesPerEUAttr TmpAttr(Context, CI, MinExpr, MaxExpr);
if (checkAMDGPUWavesPerEUArguments(*this, MinExpr, MaxExpr, TmpAttr))
return;
- D->addAttr(::new (Context) AMDGPUWavesPerEUAttr(AttrRange, Context, MinExpr,
- MaxExpr, SpellingListIndex));
+ D->addAttr(::new (Context)
+ AMDGPUWavesPerEUAttr(Context, CI, MinExpr, MaxExpr));
}
static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6013,8 +5851,7 @@ static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expr *MinExpr = AL.getArgAsExpr(0);
Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr;
- S.addAMDGPUWavesPerEUAttr(AL.getRange(), D, MinExpr, MaxExpr,
- AL.getAttributeSpellingListIndex());
+ S.addAMDGPUWavesPerEUAttr(D, AL, MinExpr, MaxExpr);
}
static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6023,9 +5860,7 @@ static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkUInt32Argument(S, AL, NumSGPRExpr, NumSGPR))
return;
- D->addAttr(::new (S.Context)
- AMDGPUNumSGPRAttr(AL.getLoc(), S.Context, NumSGPR,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AMDGPUNumSGPRAttr(S.Context, AL, NumSGPR));
}
static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6034,9 +5869,7 @@ static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkUInt32Argument(S, AL, NumVGPRExpr, NumVGPR))
return;
- D->addAttr(::new (S.Context)
- AMDGPUNumVGPRAttr(AL.getLoc(), S.Context, NumVGPR,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AMDGPUNumVGPRAttr(S.Context, AL, NumVGPR));
}
static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D,
@@ -6059,9 +5892,7 @@ static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context)
- X86ForceAlignArgPointerAttr(AL.getRange(), S.Context,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(S.Context, AL));
}
static void handleLayoutVersion(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6082,26 +5913,24 @@ static void handleLayoutVersion(Sema &S, Decl *D, const ParsedAttr &AL) {
// have to multiply by 100 now.
Version *= 100;
- D->addAttr(::new (S.Context)
- LayoutVersionAttr(AL.getRange(), S.Context, Version,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) LayoutVersionAttr(S.Context, AL, Version));
}
-DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex) {
+DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D,
+ const AttributeCommonInfo &CI) {
if (D->hasAttr<DLLExportAttr>()) {
- Diag(Range.getBegin(), diag::warn_attribute_ignored) << "'dllimport'";
+ Diag(CI.getLoc(), diag::warn_attribute_ignored) << "'dllimport'";
return nullptr;
}
if (D->hasAttr<DLLImportAttr>())
return nullptr;
- return ::new (Context) DLLImportAttr(Range, Context, AttrSpellingListIndex);
+ return ::new (Context) DLLImportAttr(Context, CI);
}
-DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range,
- unsigned AttrSpellingListIndex) {
+DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D,
+ const AttributeCommonInfo &CI) {
if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) {
Diag(Import->getLocation(), diag::warn_attribute_ignored) << Import;
D->dropAttr<DLLImportAttr>();
@@ -6110,7 +5939,7 @@ DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range,
if (D->hasAttr<DLLExportAttr>())
return nullptr;
- return ::new (Context) DLLExportAttr(Range, Context, AttrSpellingListIndex);
+ return ::new (Context) DLLExportAttr(Context, CI);
}
static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) {
@@ -6138,48 +5967,46 @@ static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) {
}
}
- unsigned Index = A.getAttributeSpellingListIndex();
Attr *NewAttr = A.getKind() == ParsedAttr::AT_DLLExport
- ? (Attr *)S.mergeDLLExportAttr(D, A.getRange(), Index)
- : (Attr *)S.mergeDLLImportAttr(D, A.getRange(), Index);
+ ? (Attr *)S.mergeDLLExportAttr(D, A)
+ : (Attr *)S.mergeDLLImportAttr(D, A);
if (NewAttr)
D->addAttr(NewAttr);
}
MSInheritanceAttr *
-Sema::mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase,
- unsigned AttrSpellingListIndex,
+Sema::mergeMSInheritanceAttr(Decl *D, const AttributeCommonInfo &CI,
+ bool BestCase,
MSInheritanceAttr::Spelling SemanticSpelling) {
if (MSInheritanceAttr *IA = D->getAttr<MSInheritanceAttr>()) {
if (IA->getSemanticSpelling() == SemanticSpelling)
return nullptr;
Diag(IA->getLocation(), diag::err_mismatched_ms_inheritance)
<< 1 /*previous declaration*/;
- Diag(Range.getBegin(), diag::note_previous_ms_inheritance);
+ Diag(CI.getLoc(), diag::note_previous_ms_inheritance);
D->dropAttr<MSInheritanceAttr>();
}
auto *RD = cast<CXXRecordDecl>(D);
if (RD->hasDefinition()) {
- if (checkMSInheritanceAttrOnDefinition(RD, Range, BestCase,
+ if (checkMSInheritanceAttrOnDefinition(RD, CI.getRange(), BestCase,
SemanticSpelling)) {
return nullptr;
}
} else {
if (isa<ClassTemplatePartialSpecializationDecl>(RD)) {
- Diag(Range.getBegin(), diag::warn_ignored_ms_inheritance)
+ Diag(CI.getLoc(), diag::warn_ignored_ms_inheritance)
<< 1 /*partial specialization*/;
return nullptr;
}
if (RD->getDescribedClassTemplate()) {
- Diag(Range.getBegin(), diag::warn_ignored_ms_inheritance)
+ Diag(CI.getLoc(), diag::warn_ignored_ms_inheritance)
<< 0 /*primary template*/;
return nullptr;
}
}
- return ::new (Context)
- MSInheritanceAttr(Range, Context, BestCase, AttrSpellingListIndex);
+ return ::new (Context) MSInheritanceAttr(Context, CI, BestCase);
}
static void handleCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6202,8 +6029,7 @@ static void handleCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!N.equals_lower("mutex") && !N.equals_lower("role"))
S.Diag(LiteralLoc, diag::warn_invalid_capability_name) << N;
- D->addAttr(::new (S.Context) CapabilityAttr(AL.getRange(), S.Context, N,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) CapabilityAttr(S.Context, AL, N));
}
static void handleAssertCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6211,9 +6037,8 @@ static void handleAssertCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!checkLockFunAttrCommon(S, D, AL, Args))
return;
- D->addAttr(::new (S.Context) AssertCapabilityAttr(AL.getRange(), S.Context,
- Args.data(), Args.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context)
+ AssertCapabilityAttr(S.Context, AL, Args.data(), Args.size()));
}
static void handleAcquireCapabilityAttr(Sema &S, Decl *D,
@@ -6222,10 +6047,8 @@ static void handleAcquireCapabilityAttr(Sema &S, Decl *D,
if (!checkLockFunAttrCommon(S, D, AL, Args))
return;
- D->addAttr(::new (S.Context) AcquireCapabilityAttr(AL.getRange(),
- S.Context,
- Args.data(), Args.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) AcquireCapabilityAttr(S.Context, AL, Args.data(),
+ Args.size()));
}
static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D,
@@ -6234,12 +6057,8 @@ static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D,
if (!checkTryLockFunAttrCommon(S, D, AL, Args))
return;
- D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(AL.getRange(),
- S.Context,
- AL.getArgAsExpr(0),
- Args.data(),
- Args.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(
+ S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size()));
}
static void handleReleaseCapabilityAttr(Sema &S, Decl *D,
@@ -6248,9 +6067,8 @@ static void handleReleaseCapabilityAttr(Sema &S, Decl *D,
SmallVector<Expr *, 1> Args;
checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 0, true);
- D->addAttr(::new (S.Context) ReleaseCapabilityAttr(
- AL.getRange(), S.Context, Args.data(), Args.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) ReleaseCapabilityAttr(S.Context, AL, Args.data(),
+ Args.size()));
}
static void handleRequiresCapabilityAttr(Sema &S, Decl *D,
@@ -6265,8 +6083,7 @@ static void handleRequiresCapabilityAttr(Sema &S, Decl *D,
return;
RequiresCapabilityAttr *RCA = ::new (S.Context)
- RequiresCapabilityAttr(AL.getRange(), S.Context, Args.data(),
- Args.size(), AL.getAttributeSpellingListIndex());
+ RequiresCapabilityAttr(S.Context, AL, Args.data(), Args.size());
D->addAttr(RCA);
}
@@ -6298,9 +6115,7 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!S.getLangOpts().CPlusPlus14 && AL.isCXX11Attribute() && !AL.isGNUScope())
S.Diag(AL.getLoc(), diag::ext_cxx14_attr) << AL;
- D->addAttr(::new (S.Context)
- DeprecatedAttr(AL.getRange(), S.Context, Str, Replacement,
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) DeprecatedAttr(S.Context, AL, Str, Replacement));
}
static bool isGlobalVar(const Decl *D) {
@@ -6331,14 +6146,13 @@ static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Sanitizers.push_back(SanitizerName);
}
- D->addAttr(::new (S.Context) NoSanitizeAttr(
- AL.getRange(), S.Context, Sanitizers.data(), Sanitizers.size(),
- AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) NoSanitizeAttr(S.Context, AL, Sanitizers.data(),
+ Sanitizers.size()));
}
static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D,
const ParsedAttr &AL) {
- StringRef AttrName = AL.getName()->getName();
+ StringRef AttrName = AL.getAttrName()->getName();
normalizeName(AttrName);
StringRef SanitizerName = llvm::StringSwitch<StringRef>(AttrName)
.Case("no_address_safety_analysis", "address")
@@ -6361,8 +6175,10 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D,
if (AL.isC2xAttribute() || AL.isCXX11Attribute())
TranslatedSpellingIndex = 1;
- D->addAttr(::new (S.Context) NoSanitizeAttr(
- AL.getRange(), S.Context, &SanitizerName, 1, TranslatedSpellingIndex));
+ AttributeCommonInfo Info = AL;
+ Info.setAttributeSpellingListIndex(TranslatedSpellingIndex);
+ D->addAttr(::new (S.Context)
+ NoSanitizeAttr(S.Context, Info, &SanitizerName, 1));
}
static void handleInternalLinkageAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
@@ -6431,7 +6247,7 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (D->getAttr<OpenCLAccessAttr>()->getSemanticSpelling() ==
AL.getSemanticSpelling()) {
S.Diag(AL.getLoc(), diag::warn_duplicate_declspec)
- << AL.getName()->getName() << AL.getRange();
+ << AL.getAttrName()->getName() << AL.getRange();
} else {
S.Diag(AL.getLoc(), diag::err_opencl_multiple_access_qualifiers)
<< D->getSourceRange();
@@ -6447,7 +6263,7 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
// qualifier is a compilation error.
if (const auto *PDecl = dyn_cast<ParmVarDecl>(D)) {
const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr();
- if (AL.getName()->getName().find("read_write") != StringRef::npos) {
+ if (AL.getAttrName()->getName().find("read_write") != StringRef::npos) {
if ((!S.getLangOpts().OpenCLCPlusPlus &&
S.getLangOpts().OpenCLVersion < 200) ||
DeclTy->isPipeType()) {
@@ -6459,8 +6275,7 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
}
}
- D->addAttr(::new (S.Context) OpenCLAccessAttr(
- AL.getRange(), S.Context, AL.getAttributeSpellingListIndex()));
+ D->addAttr(::new (S.Context) OpenCLAccessAttr(S.Context, AL));
}
static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) {
@@ -6479,9 +6294,7 @@ static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) {
static void handleUninitializedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
assert(cast<VarDecl>(D)->getStorageDuration() == SD_Automatic &&
"uninitialized is only valid on automatic duration variables");
- unsigned Index = AL.getAttributeSpellingListIndex();
- D->addAttr(::new (S.Context)
- UninitializedAttr(AL.getLoc(), S.Context, Index));
+ D->addAttr(::new (S.Context) UninitializedAttr(S.Context, AL));
}
static bool tryMakeVariablePseudoStrong(Sema &S, VarDecl *VD,
@@ -6932,9 +6745,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_CFConsumed:
case ParsedAttr::AT_NSConsumed:
case ParsedAttr::AT_OSConsumed:
- S.AddXConsumedAttr(D, AL.getRange(), AL.getAttributeSpellingListIndex(),
- parsedAttrToRetainOwnershipKind(AL),
- /*IsTemplateInstantiation=*/false);
+ S.AddXConsumedAttr(D, AL, parsedAttrToRetainOwnershipKind(AL),
+ /*IsTemplateInstantiation=*/false);
break;
case ParsedAttr::AT_NSConsumesSelf:
handleSimpleAttribute<NSConsumesSelfAttr>(S, D, AL);
@@ -6975,8 +6787,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_VecTypeHint:
handleVecTypeHint(S, D, AL);
break;
- case ParsedAttr::AT_RequireConstantInit:
- handleSimpleAttribute<RequireConstantInitAttr>(S, D, AL);
+ case ParsedAttr::AT_ConstInit:
+ handleSimpleAttribute<ConstInitAttr>(S, D, AL);
break;
case ParsedAttr::AT_InitPriority:
handleInitPriorityAttr(S, D, AL);
@@ -7116,6 +6928,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
// Interacts with -fstack-protector options.
handleSimpleAttribute<NoStackProtectorAttr>(S, D, AL);
break;
+ case ParsedAttr::AT_CFICanonicalJumpTable:
+ handleSimpleAttribute<CFICanonicalJumpTableAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_StdCall:
case ParsedAttr::AT_CDecl:
case ParsedAttr::AT_FastCall:
@@ -7136,6 +6951,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_Suppress:
handleSuppressAttr(S, D, AL);
break;
+ case ParsedAttr::AT_Owner:
+ case ParsedAttr::AT_Pointer:
+ handleLifetimeCategoryAttr(S, D, AL);
+ break;
case ParsedAttr::AT_OpenCLKernel:
handleSimpleAttribute<OpenCLKernelAttr>(S, D, AL);
break;
@@ -7146,13 +6965,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleOpenCLNoSVMAttr(S, D, AL);
break;
case ParsedAttr::AT_SwiftContext:
- handleParameterABIAttr(S, D, AL, ParameterABI::SwiftContext);
+ S.AddParameterABIAttr(D, AL, ParameterABI::SwiftContext);
break;
case ParsedAttr::AT_SwiftErrorResult:
- handleParameterABIAttr(S, D, AL, ParameterABI::SwiftErrorResult);
+ S.AddParameterABIAttr(D, AL, ParameterABI::SwiftErrorResult);
break;
case ParsedAttr::AT_SwiftIndirectResult:
- handleParameterABIAttr(S, D, AL, ParameterABI::SwiftIndirectResult);
+ S.AddParameterABIAttr(D, AL, ParameterABI::SwiftIndirectResult);
break;
case ParsedAttr::AT_InternalLinkage:
handleInternalLinkageAttr(S, D, AL);
@@ -7526,9 +7345,10 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
IdentifierInfo *NDId = ND->getIdentifier();
NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation());
- NewD->addAttr(AliasAttr::CreateImplicit(Context, NDId->getName(),
- W.getLocation()));
- NewD->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation()));
+ NewD->addAttr(
+ AliasAttr::CreateImplicit(Context, NDId->getName(), W.getLocation()));
+ NewD->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation(),
+ AttributeCommonInfo::AS_Pragma));
WeakTopLevelDecl.push_back(NewD);
// FIXME: "hideous" code from Sema::LazilyCreateBuiltin
// to insert Decl at TU scope, sorry.
@@ -7539,7 +7359,8 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
PushOnScopeChains(NewD, S);
CurContext = SavedContext;
} else { // just add weak to existing
- ND->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation()));
+ ND->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation(),
+ AttributeCommonInfo::AS_Pragma));
}
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 9a6385f28319..ff90b9548e29 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
+#include "clang/Basic/AttributeCommonInfo.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/LiteralSupport.h"
@@ -774,6 +775,13 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
return nullptr;
}
+ // C++2a [dcl.struct.bind]p1:
+ // A cv that includes volatile is deprecated
+ if ((DS.getTypeQualifiers() & DeclSpec::TQ_volatile) &&
+ getLangOpts().CPlusPlus2a)
+ Diag(DS.getVolatileSpecLoc(),
+ diag::warn_deprecated_volatile_structured_binding);
+
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType R = TInfo->getType();
@@ -1030,8 +1038,10 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T,
TemplateArgumentListInfo Args(Loc, Loc);
Args.addArgument(getTrivialTypeTemplateArgument(S, Loc, T));
- // If there's no tuple_size specialization, it's not tuple-like.
- if (lookupStdTypeTraitMember(S, R, Loc, "tuple_size", Args, /*DiagID*/0))
+ // If there's no tuple_size specialization or the lookup of 'value' is empty,
+ // it's not tuple-like.
+ if (lookupStdTypeTraitMember(S, R, Loc, "tuple_size", Args, /*DiagID*/ 0) ||
+ R.empty())
return IsTupleLike::NotTupleLike;
// If we get this far, we've committed to the tuple interpretation, but
@@ -1048,11 +1058,6 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T,
}
} Diagnoser(R, Args);
- if (R.empty()) {
- Diagnoser.diagnoseNotICE(S, Loc, SourceRange());
- return IsTupleLike::Error;
- }
-
ExprResult E =
S.BuildDeclarationNameExpr(CXXScopeSpec(), R, /*NeedsADL*/false);
if (E.isInvalid())
@@ -1228,7 +1233,8 @@ static bool checkTupleLikeDecomposition(Sema &S,
if (E.isInvalid())
return true;
RefVD->setInit(E.get());
- RefVD->checkInitIsICE();
+ if (!E.get()->isValueDependent())
+ RefVD->checkInitIsICE();
E = S.BuildDeclarationNameExpr(CXXScopeSpec(),
DeclarationNameInfo(B->getDeclName(), Loc),
@@ -1569,11 +1575,64 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
}
}
+/// Check that the given type is a literal type. Issue a diagnostic if not,
+/// if Kind is Diagnose.
+/// \return \c true if a problem has been found (and optionally diagnosed).
+template <typename... Ts>
+static bool CheckLiteralType(Sema &SemaRef, Sema::CheckConstexprKind Kind,
+ SourceLocation Loc, QualType T, unsigned DiagID,
+ Ts &&...DiagArgs) {
+ if (T->isDependentType())
+ return false;
+
+ switch (Kind) {
+ case Sema::CheckConstexprKind::Diagnose:
+ return SemaRef.RequireLiteralType(Loc, T, DiagID,
+ std::forward<Ts>(DiagArgs)...);
+
+ case Sema::CheckConstexprKind::CheckValid:
+ return !T->isLiteralType(SemaRef.Context);
+ }
+
+ llvm_unreachable("unknown CheckConstexprKind");
+}
+
+/// Determine whether a destructor cannot be constexpr due to
+static bool CheckConstexprDestructorSubobjects(Sema &SemaRef,
+ const CXXDestructorDecl *DD,
+ Sema::CheckConstexprKind Kind) {
+ auto Check = [&](SourceLocation Loc, QualType T, const FieldDecl *FD) {
+ const CXXRecordDecl *RD =
+ T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ if (!RD || RD->hasConstexprDestructor())
+ return true;
+
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(DD->getLocation(), diag::err_constexpr_dtor_subobject)
+ << DD->getConstexprKind() << !FD
+ << (FD ? FD->getDeclName() : DeclarationName()) << T;
+ SemaRef.Diag(Loc, diag::note_constexpr_dtor_subobject)
+ << !FD << (FD ? FD->getDeclName() : DeclarationName()) << T;
+ }
+ return false;
+ };
+
+ const CXXRecordDecl *RD = DD->getParent();
+ for (const CXXBaseSpecifier &B : RD->bases())
+ if (!Check(B.getBaseTypeLoc(), B.getType(), nullptr))
+ return false;
+ for (const FieldDecl *FD : RD->fields())
+ if (!Check(FD->getLocation(), FD->getType(), FD))
+ return false;
+ return true;
+}
+
// CheckConstexprParameterTypes - Check whether a function's parameter types
// are all literal types. If so, return true. If not, produce a suitable
// diagnostic and return false.
static bool CheckConstexprParameterTypes(Sema &SemaRef,
- const FunctionDecl *FD) {
+ const FunctionDecl *FD,
+ Sema::CheckConstexprKind Kind) {
unsigned ArgIndex = 0;
const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>();
for (FunctionProtoType::param_type_iterator i = FT->param_type_begin(),
@@ -1581,11 +1640,10 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef,
i != e; ++i, ++ArgIndex) {
const ParmVarDecl *PD = FD->getParamDecl(ArgIndex);
SourceLocation ParamLoc = PD->getLocation();
- if (!(*i)->isDependentType() &&
- SemaRef.RequireLiteralType(
- ParamLoc, *i, diag::err_constexpr_non_literal_param, ArgIndex + 1,
- PD->getSourceRange(), isa<CXXConstructorDecl>(FD),
- FD->isConsteval()))
+ if (CheckLiteralType(SemaRef, Kind, ParamLoc, *i,
+ diag::err_constexpr_non_literal_param, ArgIndex + 1,
+ PD->getSourceRange(), isa<CXXConstructorDecl>(FD),
+ FD->isConsteval()))
return false;
}
return true;
@@ -1605,13 +1663,18 @@ static unsigned getRecordDiagFromTagKind(TagTypeKind Tag) {
}
}
-// CheckConstexprFunctionDecl - Check whether a function declaration satisfies
-// the requirements of a constexpr function definition or a constexpr
-// constructor definition. If so, return true. If not, produce appropriate
-// diagnostics and return false.
+static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
+ Stmt *Body,
+ Sema::CheckConstexprKind Kind);
+
+// Check whether a function declaration satisfies the requirements of a
+// constexpr function definition or a constexpr constructor definition. If so,
+// return true. If not, produce appropriate diagnostics (unless asked not to by
+// Kind) and return false.
//
// This implements C++11 [dcl.constexpr]p3,4, as amended by DR1360.
-bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
+bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD,
+ CheckConstexprKind Kind) {
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
if (MD && MD->isInstance()) {
// C++11 [dcl.constexpr]p4:
@@ -1619,10 +1682,13 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
// constraints:
// - the class shall not have any virtual base classes;
//
- // FIXME: This only applies to constructors, not arbitrary member
- // functions.
+ // FIXME: This only applies to constructors and destructors, not arbitrary
+ // member functions.
const CXXRecordDecl *RD = MD->getParent();
if (RD->getNumVBases()) {
+ if (Kind == CheckConstexprKind::CheckValid)
+ return false;
+
Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base)
<< isa<CXXConstructorDecl>(NewFD)
<< getRecordDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases();
@@ -1641,8 +1707,12 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD);
if (Method && Method->isVirtual()) {
if (getLangOpts().CPlusPlus2a) {
- Diag(Method->getLocation(), diag::warn_cxx17_compat_constexpr_virtual);
+ if (Kind == CheckConstexprKind::Diagnose)
+ Diag(Method->getLocation(), diag::warn_cxx17_compat_constexpr_virtual);
} else {
+ if (Kind == CheckConstexprKind::CheckValid)
+ return false;
+
Method = Method->getCanonicalDecl();
Diag(Method->getLocation(), diag::err_constexpr_virtual);
@@ -1660,18 +1730,32 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
// - its return type shall be a literal type;
QualType RT = NewFD->getReturnType();
- if (!RT->isDependentType() &&
- RequireLiteralType(NewFD->getLocation(), RT,
- diag::err_constexpr_non_literal_return,
- NewFD->isConsteval()))
+ if (CheckLiteralType(*this, Kind, NewFD->getLocation(), RT,
+ diag::err_constexpr_non_literal_return,
+ NewFD->isConsteval()))
return false;
}
+ if (auto *Dtor = dyn_cast<CXXDestructorDecl>(NewFD)) {
+ // A destructor can be constexpr only if the defaulted destructor could be;
+ // we don't need to check the members and bases if we already know they all
+ // have constexpr destructors.
+ if (!Dtor->getParent()->defaultedDestructorIsConstexpr()) {
+ if (Kind == CheckConstexprKind::CheckValid)
+ return false;
+ if (!CheckConstexprDestructorSubobjects(*this, Dtor, Kind))
+ return false;
+ }
+ }
+
// - each of its parameter types shall be a literal type;
- if (!CheckConstexprParameterTypes(*this, NewFD))
+ if (!CheckConstexprParameterTypes(*this, NewFD, Kind))
return false;
- return true;
+ Stmt *Body = NewFD->getBody();
+ assert(Body &&
+ "CheckConstexprFunctionDefinition called on function with no body");
+ return CheckConstexprFunctionBody(*this, NewFD, Body, Kind);
}
/// Check the given declaration statement is legal within a constexpr function
@@ -1680,7 +1764,8 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) {
/// \return true if the body is OK (maybe only as an extension), false if we
/// have diagnosed a problem.
static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
- DeclStmt *DS, SourceLocation &Cxx1yLoc) {
+ DeclStmt *DS, SourceLocation &Cxx1yLoc,
+ Sema::CheckConstexprKind Kind) {
// C++11 [dcl.constexpr]p3 and p4:
// The definition of a constexpr function(p3) or constructor(p4) [...] shall
// contain only
@@ -1704,10 +1789,12 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
const auto *TN = cast<TypedefNameDecl>(DclIt);
if (TN->getUnderlyingType()->isVariablyModifiedType()) {
// Don't allow variably-modified types in constexpr functions.
- TypeLoc TL = TN->getTypeSourceInfo()->getTypeLoc();
- SemaRef.Diag(TL.getBeginLoc(), diag::err_constexpr_vla)
- << TL.getSourceRange() << TL.getType()
- << isa<CXXConstructorDecl>(Dcl);
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ TypeLoc TL = TN->getTypeSourceInfo()->getTypeLoc();
+ SemaRef.Diag(TL.getBeginLoc(), diag::err_constexpr_vla)
+ << TL.getSourceRange() << TL.getType()
+ << isa<CXXConstructorDecl>(Dcl);
+ }
return false;
}
continue;
@@ -1716,12 +1803,17 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
case Decl::Enum:
case Decl::CXXRecord:
// C++1y allows types to be defined, not just declared.
- if (cast<TagDecl>(DclIt)->isThisDeclarationADefinition())
- SemaRef.Diag(DS->getBeginLoc(),
- SemaRef.getLangOpts().CPlusPlus14
- ? diag::warn_cxx11_compat_constexpr_type_definition
- : diag::ext_constexpr_type_definition)
- << isa<CXXConstructorDecl>(Dcl);
+ if (cast<TagDecl>(DclIt)->isThisDeclarationADefinition()) {
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(DS->getBeginLoc(),
+ SemaRef.getLangOpts().CPlusPlus14
+ ? diag::warn_cxx11_compat_constexpr_type_definition
+ : diag::ext_constexpr_type_definition)
+ << isa<CXXConstructorDecl>(Dcl);
+ } else if (!SemaRef.getLangOpts().CPlusPlus14) {
+ return false;
+ }
+ }
continue;
case Decl::EnumConstant:
@@ -1735,35 +1827,47 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
case Decl::Decomposition: {
// C++1y [dcl.constexpr]p3 allows anything except:
// a definition of a variable of non-literal type or of static or
- // thread storage duration or for which no initialization is performed.
+ // thread storage duration or [before C++2a] for which no
+ // initialization is performed.
const auto *VD = cast<VarDecl>(DclIt);
if (VD->isThisDeclarationADefinition()) {
if (VD->isStaticLocal()) {
- SemaRef.Diag(VD->getLocation(),
- diag::err_constexpr_local_var_static)
- << isa<CXXConstructorDecl>(Dcl)
- << (VD->getTLSKind() == VarDecl::TLS_Dynamic);
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(VD->getLocation(),
+ diag::err_constexpr_local_var_static)
+ << isa<CXXConstructorDecl>(Dcl)
+ << (VD->getTLSKind() == VarDecl::TLS_Dynamic);
+ }
return false;
}
- if (!VD->getType()->isDependentType() &&
- SemaRef.RequireLiteralType(
- VD->getLocation(), VD->getType(),
- diag::err_constexpr_local_var_non_literal_type,
- isa<CXXConstructorDecl>(Dcl)))
+ if (CheckLiteralType(SemaRef, Kind, VD->getLocation(), VD->getType(),
+ diag::err_constexpr_local_var_non_literal_type,
+ isa<CXXConstructorDecl>(Dcl)))
return false;
if (!VD->getType()->isDependentType() &&
!VD->hasInit() && !VD->isCXXForRangeDecl()) {
- SemaRef.Diag(VD->getLocation(),
- diag::err_constexpr_local_var_no_init)
- << isa<CXXConstructorDecl>(Dcl);
- return false;
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(
+ VD->getLocation(),
+ SemaRef.getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_constexpr_local_var_no_init
+ : diag::ext_constexpr_local_var_no_init)
+ << isa<CXXConstructorDecl>(Dcl);
+ } else if (!SemaRef.getLangOpts().CPlusPlus2a) {
+ return false;
+ }
+ continue;
}
}
- SemaRef.Diag(VD->getLocation(),
- SemaRef.getLangOpts().CPlusPlus14
- ? diag::warn_cxx11_compat_constexpr_local_var
- : diag::ext_constexpr_local_var)
- << isa<CXXConstructorDecl>(Dcl);
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(VD->getLocation(),
+ SemaRef.getLangOpts().CPlusPlus14
+ ? diag::warn_cxx11_compat_constexpr_local_var
+ : diag::ext_constexpr_local_var)
+ << isa<CXXConstructorDecl>(Dcl);
+ } else if (!SemaRef.getLangOpts().CPlusPlus14) {
+ return false;
+ }
continue;
}
@@ -1776,8 +1880,10 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
continue;
default:
- SemaRef.Diag(DS->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
- << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(DS->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
+ << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
+ }
return false;
}
}
@@ -1792,17 +1898,28 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
/// struct or union nested within the class being checked.
/// \param Inits All declarations, including anonymous struct/union members and
/// indirect members, for which any initialization was provided.
-/// \param Diagnosed Set to true if an error is produced.
-static void CheckConstexprCtorInitializer(Sema &SemaRef,
+/// \param Diagnosed Whether we've emitted the error message yet. Used to attach
+/// multiple notes for different members to the same error.
+/// \param Kind Whether we're diagnosing a constructor as written or determining
+/// whether the formal requirements are satisfied.
+/// \return \c false if we're checking for validity and the constructor does
+/// not satisfy the requirements on a constexpr constructor.
+static bool CheckConstexprCtorInitializer(Sema &SemaRef,
const FunctionDecl *Dcl,
FieldDecl *Field,
llvm::SmallSet<Decl*, 16> &Inits,
- bool &Diagnosed) {
+ bool &Diagnosed,
+ Sema::CheckConstexprKind Kind) {
+ // In C++20 onwards, there's nothing to check for validity.
+ if (Kind == Sema::CheckConstexprKind::CheckValid &&
+ SemaRef.getLangOpts().CPlusPlus2a)
+ return true;
+
if (Field->isInvalidDecl())
- return;
+ return true;
if (Field->isUnnamedBitfield())
- return;
+ return true;
// Anonymous unions with no variant members and empty anonymous structs do not
// need to be explicitly initialized. FIXME: Anonymous structs that contain no
@@ -1811,22 +1928,33 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef,
(Field->getType()->isUnionType()
? !Field->getType()->getAsCXXRecordDecl()->hasVariantMembers()
: Field->getType()->getAsCXXRecordDecl()->isEmpty()))
- return;
+ return true;
if (!Inits.count(Field)) {
- if (!Diagnosed) {
- SemaRef.Diag(Dcl->getLocation(), diag::err_constexpr_ctor_missing_init);
- Diagnosed = true;
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ if (!Diagnosed) {
+ SemaRef.Diag(Dcl->getLocation(),
+ SemaRef.getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_constexpr_ctor_missing_init
+ : diag::ext_constexpr_ctor_missing_init);
+ Diagnosed = true;
+ }
+ SemaRef.Diag(Field->getLocation(),
+ diag::note_constexpr_ctor_missing_init);
+ } else if (!SemaRef.getLangOpts().CPlusPlus2a) {
+ return false;
}
- SemaRef.Diag(Field->getLocation(), diag::note_constexpr_ctor_missing_init);
} else if (Field->isAnonymousStructOrUnion()) {
const RecordDecl *RD = Field->getType()->castAs<RecordType>()->getDecl();
for (auto *I : RD->fields())
// If an anonymous union contains an anonymous struct of which any member
// is initialized, all members must be initialized.
if (!RD->isUnion() || Inits.count(I))
- CheckConstexprCtorInitializer(SemaRef, Dcl, I, Inits, Diagnosed);
+ if (!CheckConstexprCtorInitializer(SemaRef, Dcl, I, Inits, Diagnosed,
+ Kind))
+ return false;
}
+ return true;
}
/// Check the provided statement is allowed in a constexpr function
@@ -1834,7 +1962,8 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef,
static bool
CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
SmallVectorImpl<SourceLocation> &ReturnStmts,
- SourceLocation &Cxx1yLoc, SourceLocation &Cxx2aLoc) {
+ SourceLocation &Cxx1yLoc, SourceLocation &Cxx2aLoc,
+ Sema::CheckConstexprKind Kind) {
// - its function-body shall be [...] a compound-statement that contains only
switch (S->getStmtClass()) {
case Stmt::NullStmtClass:
@@ -1847,7 +1976,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
// - using-directives,
// - typedef declarations and alias-declarations that do not define
// classes or enumerations,
- if (!CheckConstexprDeclStmt(SemaRef, Dcl, cast<DeclStmt>(S), Cxx1yLoc))
+ if (!CheckConstexprDeclStmt(SemaRef, Dcl, cast<DeclStmt>(S), Cxx1yLoc, Kind))
return false;
return true;
@@ -1871,7 +2000,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
CompoundStmt *CompStmt = cast<CompoundStmt>(S);
for (auto *BodyIt : CompStmt->body()) {
if (!CheckConstexprFunctionStmt(SemaRef, Dcl, BodyIt, ReturnStmts,
- Cxx1yLoc, Cxx2aLoc))
+ Cxx1yLoc, Cxx2aLoc, Kind))
return false;
}
return true;
@@ -1889,11 +2018,11 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
IfStmt *If = cast<IfStmt>(S);
if (!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getThen(), ReturnStmts,
- Cxx1yLoc, Cxx2aLoc))
+ Cxx1yLoc, Cxx2aLoc, Kind))
return false;
if (If->getElse() &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getElse(), ReturnStmts,
- Cxx1yLoc, Cxx2aLoc))
+ Cxx1yLoc, Cxx2aLoc, Kind))
return false;
return true;
}
@@ -1912,7 +2041,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
for (Stmt *SubStmt : S->children())
if (SubStmt &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
- Cxx1yLoc, Cxx2aLoc))
+ Cxx1yLoc, Cxx2aLoc, Kind))
return false;
return true;
@@ -1927,17 +2056,20 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
for (Stmt *SubStmt : S->children())
if (SubStmt &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
- Cxx1yLoc, Cxx2aLoc))
+ Cxx1yLoc, Cxx2aLoc, Kind))
return false;
return true;
+ case Stmt::GCCAsmStmtClass:
+ case Stmt::MSAsmStmtClass:
+ // C++2a allows inline assembly statements.
case Stmt::CXXTryStmtClass:
if (Cxx2aLoc.isInvalid())
Cxx2aLoc = S->getBeginLoc();
for (Stmt *SubStmt : S->children()) {
if (SubStmt &&
!CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
- Cxx1yLoc, Cxx2aLoc))
+ Cxx1yLoc, Cxx2aLoc, Kind))
return false;
}
return true;
@@ -1947,7 +2079,7 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
// try block check).
if (!CheckConstexprFunctionStmt(SemaRef, Dcl,
cast<CXXCatchStmt>(S)->getHandlerBlock(),
- ReturnStmts, Cxx1yLoc, Cxx2aLoc))
+ ReturnStmts, Cxx1yLoc, Cxx2aLoc, Kind))
return false;
return true;
@@ -1961,16 +2093,21 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
return true;
}
- SemaRef.Diag(S->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
- << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(S->getBeginLoc(), diag::err_constexpr_body_invalid_stmt)
+ << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval();
+ }
return false;
}
/// Check the body for the given constexpr function declaration only contains
/// the permitted types of statement. C++11 [dcl.constexpr]p3,p4.
///
-/// \return true if the body is OK, false if we have diagnosed a problem.
-bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
+/// \return true if the body is OK, false if we have found or diagnosed a
+/// problem.
+static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl,
+ Stmt *Body,
+ Sema::CheckConstexprKind Kind) {
SmallVector<SourceLocation, 4> ReturnStmts;
if (isa<CXXTryStmt>(Body)) {
@@ -1986,11 +2123,20 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
//
// This restriction is lifted in C++2a, as long as inner statements also
// apply the general constexpr rules.
- Diag(Body->getBeginLoc(),
- !getLangOpts().CPlusPlus2a
- ? diag::ext_constexpr_function_try_block_cxx2a
- : diag::warn_cxx17_compat_constexpr_function_try_block)
- << isa<CXXConstructorDecl>(Dcl);
+ switch (Kind) {
+ case Sema::CheckConstexprKind::CheckValid:
+ if (!SemaRef.getLangOpts().CPlusPlus2a)
+ return false;
+ break;
+
+ case Sema::CheckConstexprKind::Diagnose:
+ SemaRef.Diag(Body->getBeginLoc(),
+ !SemaRef.getLangOpts().CPlusPlus2a
+ ? diag::ext_constexpr_function_try_block_cxx2a
+ : diag::warn_cxx17_compat_constexpr_function_try_block)
+ << isa<CXXConstructorDecl>(Dcl);
+ break;
+ }
}
// - its function-body shall be [...] a compound-statement that contains only
@@ -2001,23 +2147,30 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
SourceLocation Cxx1yLoc, Cxx2aLoc;
for (Stmt *SubStmt : Body->children()) {
if (SubStmt &&
- !CheckConstexprFunctionStmt(*this, Dcl, SubStmt, ReturnStmts,
- Cxx1yLoc, Cxx2aLoc))
+ !CheckConstexprFunctionStmt(SemaRef, Dcl, SubStmt, ReturnStmts,
+ Cxx1yLoc, Cxx2aLoc, Kind))
return false;
}
- if (Cxx2aLoc.isValid())
- Diag(Cxx2aLoc,
- getLangOpts().CPlusPlus2a
+ if (Kind == Sema::CheckConstexprKind::CheckValid) {
+ // If this is only valid as an extension, report that we don't satisfy the
+ // constraints of the current language.
+ if ((Cxx2aLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus2a) ||
+ (Cxx1yLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus17))
+ return false;
+ } else if (Cxx2aLoc.isValid()) {
+ SemaRef.Diag(Cxx2aLoc,
+ SemaRef.getLangOpts().CPlusPlus2a
? diag::warn_cxx17_compat_constexpr_body_invalid_stmt
: diag::ext_constexpr_body_invalid_stmt_cxx2a)
<< isa<CXXConstructorDecl>(Dcl);
- if (Cxx1yLoc.isValid())
- Diag(Cxx1yLoc,
- getLangOpts().CPlusPlus14
+ } else if (Cxx1yLoc.isValid()) {
+ SemaRef.Diag(Cxx1yLoc,
+ SemaRef.getLangOpts().CPlusPlus14
? diag::warn_cxx11_compat_constexpr_body_invalid_stmt
: diag::ext_constexpr_body_invalid_stmt)
<< isa<CXXConstructorDecl>(Dcl);
+ }
if (const CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(Dcl)) {
@@ -2031,8 +2184,15 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
if (RD->isUnion()) {
if (Constructor->getNumCtorInitializers() == 0 &&
RD->hasVariantMembers()) {
- Diag(Dcl->getLocation(), diag::err_constexpr_union_ctor_no_init);
- return false;
+ if (Kind == Sema::CheckConstexprKind::Diagnose) {
+ SemaRef.Diag(
+ Dcl->getLocation(),
+ SemaRef.getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_constexpr_union_ctor_no_init
+ : diag::ext_constexpr_union_ctor_no_init);
+ } else if (!SemaRef.getLangOpts().CPlusPlus2a) {
+ return false;
+ }
}
} else if (!Constructor->isDependentContext() &&
!Constructor->isDelegatingConstructor()) {
@@ -2068,9 +2228,9 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
bool Diagnosed = false;
for (auto *I : RD->fields())
- CheckConstexprCtorInitializer(*this, Dcl, I, Inits, Diagnosed);
- if (Diagnosed)
- return false;
+ if (!CheckConstexprCtorInitializer(SemaRef, Dcl, I, Inits, Diagnosed,
+ Kind))
+ return false;
}
}
} else {
@@ -2079,22 +2239,45 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
// statement. We still do, unless the return type might be void, because
// otherwise if there's no return statement, the function cannot
// be used in a core constant expression.
- bool OK = getLangOpts().CPlusPlus14 &&
+ bool OK = SemaRef.getLangOpts().CPlusPlus14 &&
(Dcl->getReturnType()->isVoidType() ||
Dcl->getReturnType()->isDependentType());
- Diag(Dcl->getLocation(),
- OK ? diag::warn_cxx11_compat_constexpr_body_no_return
- : diag::err_constexpr_body_no_return)
- << Dcl->isConsteval();
- if (!OK)
- return false;
+ switch (Kind) {
+ case Sema::CheckConstexprKind::Diagnose:
+ SemaRef.Diag(Dcl->getLocation(),
+ OK ? diag::warn_cxx11_compat_constexpr_body_no_return
+ : diag::err_constexpr_body_no_return)
+ << Dcl->isConsteval();
+ if (!OK)
+ return false;
+ break;
+
+ case Sema::CheckConstexprKind::CheckValid:
+ // The formal requirements don't include this rule in C++14, even
+ // though the "must be able to produce a constant expression" rules
+ // still imply it in some cases.
+ if (!SemaRef.getLangOpts().CPlusPlus14)
+ return false;
+ break;
+ }
} else if (ReturnStmts.size() > 1) {
- Diag(ReturnStmts.back(),
- getLangOpts().CPlusPlus14
- ? diag::warn_cxx11_compat_constexpr_body_multiple_return
- : diag::ext_constexpr_body_multiple_return);
- for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I)
- Diag(ReturnStmts[I], diag::note_constexpr_body_previous_return);
+ switch (Kind) {
+ case Sema::CheckConstexprKind::Diagnose:
+ SemaRef.Diag(
+ ReturnStmts.back(),
+ SemaRef.getLangOpts().CPlusPlus14
+ ? diag::warn_cxx11_compat_constexpr_body_multiple_return
+ : diag::ext_constexpr_body_multiple_return);
+ for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I)
+ SemaRef.Diag(ReturnStmts[I],
+ diag::note_constexpr_body_previous_return);
+ break;
+
+ case Sema::CheckConstexprKind::CheckValid:
+ if (!SemaRef.getLangOpts().CPlusPlus14)
+ return false;
+ break;
+ }
}
}
@@ -2108,12 +2291,17 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
// C++11 [dcl.constexpr]p4:
// - every constructor involved in initializing non-static data members and
// base class sub-objects shall be a constexpr constructor.
+ //
+ // Note that this rule is distinct from the "requirements for a constexpr
+ // function", so is not checked in CheckValid mode.
SmallVector<PartialDiagnosticAt, 8> Diags;
- if (!Expr::isPotentialConstantExpr(Dcl, Diags)) {
- Diag(Dcl->getLocation(), diag::ext_constexpr_function_never_constant_expr)
- << isa<CXXConstructorDecl>(Dcl);
+ if (Kind == Sema::CheckConstexprKind::Diagnose &&
+ !Expr::isPotentialConstantExpr(Dcl, Diags)) {
+ SemaRef.Diag(Dcl->getLocation(),
+ diag::ext_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);
+ SemaRef.Diag(Diags[I].first, Diags[I].second);
// Don't return false here: we allow this for compatibility in
// system headers.
}
@@ -2298,7 +2486,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
}
// If the base class is polymorphic or isn't empty, the new one is/isn't, too.
- RecordDecl *BaseDecl = BaseType->getAs<RecordType>()->getDecl();
+ RecordDecl *BaseDecl = BaseType->castAs<RecordType>()->getDecl();
assert(BaseDecl && "Record type has no declaration");
BaseDecl = BaseDecl->getDefinition();
assert(BaseDecl && "Base type is not incomplete, but has no definition");
@@ -2381,7 +2569,7 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
Diag(AL.getLoc(), AL.getKind() == ParsedAttr::UnknownAttribute
? (unsigned)diag::warn_unknown_attribute_ignored
: (unsigned)diag::err_base_specifier_attribute)
- << AL.getName();
+ << AL;
}
TypeSourceInfo *TInfo = nullptr;
@@ -3225,10 +3413,12 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
}
if (VS.isOverrideSpecified())
- Member->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context, 0));
+ Member->addAttr(OverrideAttr::Create(Context, VS.getOverrideLoc(),
+ AttributeCommonInfo::AS_Keyword));
if (VS.isFinalSpecified())
- Member->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context,
- VS.isFinalSpelledSealed()));
+ Member->addAttr(FinalAttr::Create(
+ Context, VS.getFinalLoc(), AttributeCommonInfo::AS_Keyword,
+ static_cast<FinalAttr::Spelling>(VS.isFinalSpelledSealed())));
if (VS.getLastLocation().isValid()) {
// Update the end location of a method that has a virt-specifiers.
@@ -3826,7 +4016,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<MemInitializerValidatorCCC>(*this);
+ return std::make_unique<MemInitializerValidatorCCC>(*this);
}
private:
@@ -5801,14 +5991,10 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
TSK != TSK_ExplicitInstantiationDefinition) {
if (ClassExported) {
NewAttr = ::new (getASTContext())
- DLLExportStaticLocalAttr(ClassAttr->getRange(),
- getASTContext(),
- ClassAttr->getSpellingListIndex());
+ DLLExportStaticLocalAttr(getASTContext(), *ClassAttr);
} else {
NewAttr = ::new (getASTContext())
- DLLImportStaticLocalAttr(ClassAttr->getRange(),
- getASTContext(),
- ClassAttr->getSpellingListIndex());
+ DLLImportStaticLocalAttr(getASTContext(), *ClassAttr);
}
} else {
NewAttr = cast<InheritableAttr>(ClassAttr->clone(getASTContext()));
@@ -6117,6 +6303,22 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
}
+ // Warn if the class has a final destructor but is not itself marked final.
+ if (!Record->hasAttr<FinalAttr>()) {
+ if (const CXXDestructorDecl *dtor = Record->getDestructor()) {
+ if (const FinalAttr *FA = dtor->getAttr<FinalAttr>()) {
+ Diag(FA->getLocation(), diag::warn_final_dtor_non_final_class)
+ << FA->isSpelledAsSealed()
+ << FixItHint::CreateInsertion(
+ getLocForEndOfToken(Record->getLocation()),
+ (FA->isSpelledAsSealed() ? " sealed" : " final"));
+ Diag(Record->getLocation(),
+ diag::note_final_dtor_non_final_class_silence)
+ << Context.getRecordType(Record) << FA->isSpelledAsSealed();
+ }
+ }
+ }
+
// See if trivial_abi has to be dropped.
if (Record->hasAttr<TrivialABIAttr>())
checkIllFormedTrivialABIStruct(*Record);
@@ -6165,10 +6367,16 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
M->dropAttr<DLLExportAttr>();
if (M->hasAttr<DLLExportAttr>()) {
- DefineImplicitSpecialMember(*this, M, M->getLocation());
- ActOnFinishInlineFunctionDef(M);
+ // Define after any fields with in-class initializers have been parsed.
+ DelayedDllExportMemberFunctions.push_back(M);
}
}
+
+ // Define defaulted constexpr virtual functions that override a base class
+ // function right away.
+ // FIXME: We can defer doing this until the vtable is marked as used.
+ if (M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods())
+ DefineImplicitSpecialMember(*this, M, M->getLocation());
};
bool HasMethodWithOverrideControl = false,
@@ -6382,6 +6590,8 @@ specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
if (CSM == Sema::CXXDefaultConstructor)
return ClassDecl->hasConstexprDefaultConstructor();
+ if (CSM == Sema::CXXDestructor)
+ return ClassDecl->hasConstexprDestructor();
Sema::SpecialMemberOverloadResult SMOR =
lookupCallFromSpecialMember(S, ClassDecl, CSM, Quals, ConstRHS);
@@ -6430,6 +6640,8 @@ static bool defaultedSpecialMemberIsConstexpr(
break;
case Sema::CXXDestructor:
+ return ClassDecl->defaultedDestructorIsConstexpr();
+
case Sema::CXXInvalid:
return false;
}
@@ -6682,13 +6894,14 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// Do not apply this rule to members of class templates, since core issue 1358
// makes such functions always instantiate to constexpr functions. For
// functions which cannot be constexpr (for non-constructors in C++11 and for
- // destructors in C++1y), this is checked elsewhere.
+ // destructors in C++14 and C++17), this is checked elsewhere.
//
// FIXME: This should not apply if the member is deleted.
bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM,
HasConstParam);
- if ((getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD)
- : isa<CXXConstructorDecl>(MD)) &&
+ if ((getLangOpts().CPlusPlus2a ||
+ (getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD)
+ : isa<CXXConstructorDecl>(MD))) &&
MD->isConstexpr() && !Constexpr &&
MD->getTemplatedKind() == FunctionDecl::TK_NonTemplate) {
Diag(MD->getBeginLoc(), MD->isConsteval()
@@ -7798,7 +8011,7 @@ public:
/// to be used with CXXRecordDecl::lookupInBases().
bool operator()(const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
RecordDecl *BaseRecord =
- Specifier->getType()->getAs<RecordType>()->getDecl();
+ Specifier->getType()->castAs<RecordType>()->getDecl();
DeclarationName Name = Method->getDeclName();
assert(Name.getNameKind() == DeclarationName::Identifier);
@@ -7966,8 +8179,7 @@ void Sema::ActOnFinishCXXMemberSpecification(
if (AL.getKind() != ParsedAttr::AT_Visibility)
continue;
AL.setInvalid();
- Diag(AL.getLoc(), diag::warn_attribute_after_definition_ignored)
- << AL.getName();
+ Diag(AL.getLoc(), diag::warn_attribute_after_definition_ignored) << AL;
}
ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef(
@@ -9386,7 +9598,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<NamespaceValidatorCCC>(*this);
+ return std::make_unique<NamespaceValidatorCCC>(*this);
}
};
@@ -9882,7 +10094,8 @@ static CXXBaseSpecifier *findDirectBaseWithType(CXXRecordDecl *Derived,
QualType DesiredBase,
bool &AnyDependentBases) {
// Check whether the named type is a direct base class.
- CanQualType CanonicalDesiredBase = DesiredBase->getCanonicalTypeUnqualified();
+ CanQualType CanonicalDesiredBase = DesiredBase->getCanonicalTypeUnqualified()
+ .getUnqualifiedType();
for (auto &Base : Derived->bases()) {
CanQualType BaseType = Base.getType()->getCanonicalTypeUnqualified();
if (CanonicalDesiredBase == BaseType)
@@ -9965,7 +10178,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<UsingValidatorCCC>(*this);
+ return std::make_unique<UsingValidatorCCC>(*this);
}
private:
@@ -11311,6 +11524,10 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
if (DSM.isAlreadyBeingDeclared())
return nullptr;
+ bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,
+ CXXDestructor,
+ false);
+
// Create the actual destructor declaration.
CanQualType ClassType
= Context.getCanonicalType(Context.getTypeDeclType(ClassDecl));
@@ -11318,10 +11535,11 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
DeclarationName Name
= Context.DeclarationNames.getCXXDestructorName(ClassType);
DeclarationNameInfo NameInfo(Name, ClassLoc);
- CXXDestructorDecl *Destructor
- = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
- QualType(), nullptr, /*isInline=*/true,
- /*isImplicitlyDeclared=*/true);
+ CXXDestructorDecl *Destructor =
+ CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo,
+ QualType(), nullptr, /*isInline=*/true,
+ /*isImplicitlyDeclared=*/true,
+ Constexpr ? CSK_constexpr : CSK_unspecified);
Destructor->setAccess(AS_public);
Destructor->setDefaulted();
@@ -11419,6 +11637,21 @@ void Sema::ActOnFinishCXXMemberDecls() {
void Sema::ActOnFinishCXXNonNestedClass(Decl *D) {
referenceDLLExportedClassMethods();
+
+ if (!DelayedDllExportMemberFunctions.empty()) {
+ SmallVector<CXXMethodDecl*, 4> WorkList;
+ std::swap(DelayedDllExportMemberFunctions, WorkList);
+ for (CXXMethodDecl *M : WorkList) {
+ DefineImplicitSpecialMember(*this, M, M->getLocation());
+
+ // Pass the method to the consumer to get emitted. This is not necessary
+ // for explicit instantiation definitions, as they will get emitted
+ // anyway.
+ if (M->getParent()->getTemplateSpecializationKind() !=
+ TSK_ExplicitInstantiationDefinition)
+ ActOnFinishInlineFunctionDef(M);
+ }
+ }
}
void Sema::referenceDLLExportedClassMethods() {
@@ -11619,7 +11852,8 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
const Type *E = T->getBaseElementTypeUnsafe();
bool NeedsCollectableMemCpy =
- E->isRecordType() && E->getAs<RecordType>()->getDecl()->hasObjectMember();
+ E->isRecordType() &&
+ E->castAs<RecordType>()->getDecl()->hasObjectMember();
// Create a reference to the __builtin_objc_memmove_collectable function
StringRef MemCpyName = NeedsCollectableMemCpy ?
@@ -13172,6 +13406,20 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
}
if (Destructor->isTrivial()) return;
+
+ // If the destructor is constexpr, check whether the variable has constant
+ // destruction now.
+ if (Destructor->isConstexpr() && VD->getInit() &&
+ !VD->getInit()->isValueDependent() && VD->evaluateValue()) {
+ SmallVector<PartialDiagnosticAt, 8> Notes;
+ if (!VD->evaluateDestruction(Notes) && VD->isConstexpr()) {
+ Diag(VD->getLocation(),
+ diag::err_constexpr_var_requires_const_destruction) << VD;
+ for (unsigned I = 0, N = Notes.size(); I != N; ++I)
+ Diag(Notes[I].first, Notes[I].second);
+ }
+ }
+
if (!VD->hasGlobalStorage()) return;
// Emit warning for non-trivial dtor in global scope (a real global,
@@ -13762,6 +14010,10 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc,
Language = LinkageSpecDecl::lang_c;
else if (Lang == "C++")
Language = LinkageSpecDecl::lang_cxx;
+ else if (Lang == "C++11")
+ Language = LinkageSpecDecl::lang_cxx_11;
+ else if (Lang == "C++14")
+ Language = LinkageSpecDecl::lang_cxx_14;
else {
Diag(LangStr->getExprLoc(), diag::err_language_linkage_spec_unknown)
<< LangStr->getSourceRange();
@@ -14014,8 +14266,17 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
if (Converted.isInvalid())
Failed = true;
+ ExprResult FullAssertExpr =
+ ActOnFinishFullExpr(Converted.get(), StaticAssertLoc,
+ /*DiscardedValue*/ false,
+ /*IsConstexpr*/ true);
+ if (FullAssertExpr.isInvalid())
+ Failed = true;
+ else
+ AssertExpr = FullAssertExpr.get();
+
llvm::APSInt Cond;
- if (!Failed && VerifyIntegerConstantExpression(Converted.get(), &Cond,
+ if (!Failed && VerifyIntegerConstantExpression(AssertExpr, &Cond,
diag::err_static_assert_expression_is_not_constant,
/*AllowFold=*/false).isInvalid())
Failed = true;
@@ -14041,16 +14302,16 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
}
Failed = true;
}
+ } else {
+ ExprResult FullAssertExpr = ActOnFinishFullExpr(AssertExpr, StaticAssertLoc,
+ /*DiscardedValue*/false,
+ /*IsConstexpr*/true);
+ if (FullAssertExpr.isInvalid())
+ Failed = true;
+ else
+ AssertExpr = FullAssertExpr.get();
}
- ExprResult FullAssertExpr = ActOnFinishFullExpr(AssertExpr, StaticAssertLoc,
- /*DiscardedValue*/false,
- /*IsConstexpr*/true);
- if (FullAssertExpr.isInvalid())
- Failed = true;
- else
- AssertExpr = FullAssertExpr.get();
-
Decl *Decl = StaticAssertDecl::Create(Context, CurContext, StaticAssertLoc,
AssertExpr, AssertMessage, RParenLoc,
Failed);
@@ -15282,8 +15543,8 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc,
return;
for (const auto &I : RD->bases()) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const auto *Base =
+ cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
if (Base->getNumVBases() == 0)
continue;
MarkVirtualMembersReferenced(Loc, Base);
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index e629837eb71d..db594bbd21dd 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -512,7 +512,7 @@ class ObjCInterfaceValidatorCCC final : public CorrectionCandidateCallback {
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<ObjCInterfaceValidatorCCC>(*this);
+ return std::make_unique<ObjCInterfaceValidatorCCC>(*this);
}
private:
@@ -586,7 +586,7 @@ ActOnSuperClassOfClassInterface(Scope *S,
dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) {
QualType T = TDecl->getUnderlyingType();
if (T->isObjCObjectType()) {
- if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) {
+ if (NamedDecl *IDecl = T->castAs<ObjCObjectType>()->getInterface()) {
SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl);
SuperClassType = Context.getTypeDeclType(TDecl);
@@ -1151,7 +1151,7 @@ Decl *Sema::ActOnCompatibilityAlias(SourceLocation AtLoc,
dyn_cast_or_null<TypedefNameDecl>(CDeclU)) {
QualType T = TDecl->getUnderlyingType();
if (T->isObjCObjectType()) {
- if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) {
+ if (NamedDecl *IDecl = T->castAs<ObjCObjectType>()->getInterface()) {
ClassName = IDecl->getIdentifier();
CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation,
LookupOrdinaryName,
@@ -1387,7 +1387,7 @@ class ObjCTypeArgOrProtocolValidatorCCC final
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(*this);
+ return std::make_unique<ObjCTypeArgOrProtocolValidatorCCC>(*this);
}
};
} // end anonymous namespace
@@ -2275,9 +2275,7 @@ static bool isObjCTypeSubstitutable(ASTContext &Context,
// stricter definition so it is not substitutable for id<A>.
if (B->isObjCQualifiedIdType()) {
return A->isObjCQualifiedIdType() &&
- Context.ObjCQualifiedIdTypesAreCompatible(QualType(A, 0),
- QualType(B,0),
- false);
+ Context.ObjCQualifiedIdTypesAreCompatible(A, B, false);
}
/*
@@ -4878,7 +4876,7 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T,
} else if (!T->isObjCObjectPointerType()) {
Invalid = true;
Diag(IdLoc, diag::err_catch_param_not_objc_type);
- } else if (!T->getAs<ObjCObjectPointerType>()->getInterfaceType()) {
+ } else if (!T->castAs<ObjCObjectPointerType>()->getInterfaceType()) {
Invalid = true;
Diag(IdLoc, diag::err_catch_param_not_objc_type);
}
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 9fd924a8cad0..c1abf099e9f2 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -149,12 +149,12 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
// In Microsoft mode, downgrade this to a warning.
unsigned DiagID = diag::err_incomplete_in_exception_spec;
bool ReturnValueOnError = true;
- if (getLangOpts().MicrosoftExt) {
+ if (getLangOpts().MSVCCompat) {
DiagID = diag::ext_incomplete_in_exception_spec;
ReturnValueOnError = false;
}
if (!(PointeeT->isRecordType() &&
- PointeeT->getAs<RecordType>()->isBeingDefined()) &&
+ PointeeT->castAs<RecordType>()->isBeingDefined()) &&
RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range))
return ReturnValueOnError;
@@ -263,8 +263,7 @@ static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
if (!Decl->getTypeSourceInfo())
return isa<CXXDestructorDecl>(Decl);
- const FunctionProtoType *Ty =
- Decl->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>();
+ auto *Ty = Decl->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>();
return !Ty->hasExceptionSpec();
}
@@ -282,7 +281,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
unsigned DiagID = diag::err_mismatched_exception_spec;
bool ReturnValueOnError = true;
- if (getLangOpts().MicrosoftExt) {
+ if (getLangOpts().MSVCCompat) {
DiagID = diag::ext_mismatched_exception_spec;
ReturnValueOnError = false;
}
@@ -371,7 +370,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
NewProto->getExtProtoInfo().withExceptionSpec(ESI)));
}
- if (getLangOpts().MicrosoftExt && ESI.Type != EST_DependentNoexcept) {
+ if (getLangOpts().MSVCCompat && ESI.Type != EST_DependentNoexcept) {
// Allow missing exception specifications in redeclarations as an extension.
DiagID = diag::ext_ms_missing_exception_specification;
ReturnValueOnError = false;
@@ -473,14 +472,14 @@ bool Sema::CheckEquivalentExceptionSpec(
return false;
unsigned DiagID = diag::err_mismatched_exception_spec;
- if (getLangOpts().MicrosoftExt)
+ if (getLangOpts().MSVCCompat)
DiagID = diag::ext_mismatched_exception_spec;
bool Result = CheckEquivalentExceptionSpecImpl(
*this, PDiag(DiagID), PDiag(diag::note_previous_declaration),
Old, OldLoc, New, NewLoc);
// In Microsoft mode, mismatching exception specifications just cause a warning.
- if (getLangOpts().MicrosoftExt)
+ if (getLangOpts().MSVCCompat)
return false;
return Result;
}
@@ -959,15 +958,15 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
}
unsigned DiagID = diag::err_override_exception_spec;
- if (getLangOpts().MicrosoftExt)
+ if (getLangOpts().MSVCCompat)
DiagID = diag::ext_override_exception_spec;
return CheckExceptionSpecSubset(PDiag(DiagID),
PDiag(diag::err_deep_exception_specs_differ),
PDiag(diag::note_overridden_virtual_function),
PDiag(diag::ext_override_exception_spec),
- Old->getType()->getAs<FunctionProtoType>(),
+ Old->getType()->castAs<FunctionProtoType>(),
Old->getLocation(),
- New->getType()->getAs<FunctionProtoType>(),
+ New->getType()->castAs<FunctionProtoType>(),
New->getLocation());
}
@@ -1201,6 +1200,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::CoyieldExprClass:
case Expr::CXXConstCastExprClass:
case Expr::CXXReinterpretCastExprClass:
+ case Expr::CXXRewrittenBinaryOperatorClass:
case Expr::BuiltinBitCastExprClass:
case Expr::CXXStdInitializerListExprClass:
case Expr::DesignatedInitExprClass:
@@ -1314,6 +1314,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::SizeOfPackExprClass:
case Expr::StringLiteralClass:
case Expr::SourceLocExprClass:
+ case Expr::ConceptSpecializationExprClass:
// These expressions can never throw.
return CT_Cannot;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index d8869ffe945a..e41cd5b6653a 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1990,16 +1990,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
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().MSVCCompat && isa<FunctionDecl>(DC) &&
- cast<FunctionDecl>(DC)->getFriendObjectKind() &&
- DC->getLexicalParent()->isRecord())
- DC = DC->getLexicalParent();
- else
- DC = DC->getParent();
+ DC = DC->getLookupParent();
}
// We didn't find anything, so try to correct for a typo.
@@ -2491,23 +2482,20 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr(
return BuildDeclarationNameExpr(SS, R, /* ADL */ false);
}
-/// LookupInObjCMethod - The parser has read a name in, and Sema has
-/// detected that we're currently inside an ObjC method. Perform some
-/// additional lookup.
+/// The parser has read a name in, and Sema has detected that we're currently
+/// inside an ObjC method. Perform some additional checks and determine if we
+/// should form a reference to an ivar.
///
/// Ideally, most of this would be done by lookup, but there's
/// actually quite a lot of extra work involved.
-///
-/// Returns a null sentinel to indicate trivial success.
-ExprResult
-Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
- IdentifierInfo *II, bool AllowBuiltinCreation) {
+DeclResult Sema::LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S,
+ IdentifierInfo *II) {
SourceLocation Loc = Lookup.getNameLoc();
ObjCMethodDecl *CurMethod = getCurMethodDecl();
// Check for error condition which is already reported.
if (!CurMethod)
- return ExprError();
+ return DeclResult(true);
// There are two cases to handle here. 1) scoped lookup could have failed,
// in which case we should look for an ivar. 2) scoped lookup could have
@@ -2535,18 +2523,10 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
ObjCIvarDecl *IV = nullptr;
if (IFace && (IV = IFace->lookupInstanceVariable(II, ClassDeclared))) {
// Diagnose using an ivar in a class method.
- if (IsClassMethod)
- return ExprError(Diag(Loc, diag::err_ivar_use_in_class_method)
- << IV->getDeclName());
-
- // If we're referencing an invalid decl, just return this as a silent
- // error node. The error diagnostic was already emitted on the decl.
- if (IV->isInvalidDecl())
- return ExprError();
-
- // Check if referencing a field with __attribute__((deprecated)).
- if (DiagnoseUseOfDecl(IV, Loc))
- return ExprError();
+ if (IsClassMethod) {
+ Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName();
+ return DeclResult(true);
+ }
// Diagnose the use of an ivar outside of the declaring class.
if (IV->getAccessControl() == ObjCIvarDecl::Private &&
@@ -2554,46 +2534,8 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
!getLangOpts().DebuggerSupport)
Diag(Loc, diag::err_private_ivar_access) << IV->getDeclName();
- // FIXME: This should use a new expr for a direct reference, don't
- // turn this into Self->ivar, just return a BareIVarExpr or something.
- IdentifierInfo &II = Context.Idents.get("self");
- UnqualifiedId SelfName;
- SelfName.setIdentifier(&II, SourceLocation());
- SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam);
- CXXScopeSpec SelfScopeSpec;
- SourceLocation TemplateKWLoc;
- ExprResult SelfExpr =
- ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName,
- /*HasTrailingLParen=*/false,
- /*IsAddressOfOperand=*/false);
- if (SelfExpr.isInvalid())
- return ExprError();
-
- SelfExpr = DefaultLvalueConversion(SelfExpr.get());
- if (SelfExpr.isInvalid())
- return ExprError();
-
- MarkAnyDeclReferenced(Loc, IV, true);
-
- ObjCMethodFamily MF = CurMethod->getMethodFamily();
- if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize &&
- !IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV))
- Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName();
-
- ObjCIvarRefExpr *Result = new (Context)
- ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc,
- IV->getLocation(), SelfExpr.get(), true, true);
-
- if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
- if (!isUnevaluatedContext() &&
- !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
- getCurFunction()->recordUseOfWeak(Result);
- }
- if (getLangOpts().ObjCAutoRefCount)
- if (const BlockDecl *BD = CurContext->getInnermostBlockDecl())
- ImplicitlyRetainedSelfLocs.push_back({Loc, BD});
-
- return Result;
+ // Success.
+ return IV;
}
} else if (CurMethod->isInstanceMethod()) {
// We should warn if a local variable hides an ivar.
@@ -2608,25 +2550,97 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
} 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::err_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 (!(getLangOpts().CPlusPlus &&
- Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))) {
- NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID,
- S, Lookup.isForRedeclaration(),
- Lookup.getNameLoc());
- if (D) Lookup.addDecl(D);
- }
+ if (const ObjCIvarDecl *IV =
+ dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl())) {
+ Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName();
+ return DeclResult(true);
}
}
+
+ // Didn't encounter an error, didn't find an ivar.
+ return DeclResult(false);
+}
+
+ExprResult Sema::BuildIvarRefExpr(Scope *S, SourceLocation Loc,
+ ObjCIvarDecl *IV) {
+ ObjCMethodDecl *CurMethod = getCurMethodDecl();
+ assert(CurMethod && CurMethod->isInstanceMethod() &&
+ "should not reference ivar from this context");
+
+ ObjCInterfaceDecl *IFace = CurMethod->getClassInterface();
+ assert(IFace && "should not reference ivar from this context");
+
+ // If we're referencing an invalid decl, just return this as a silent
+ // error node. The error diagnostic was already emitted on the decl.
+ if (IV->isInvalidDecl())
+ return ExprError();
+
+ // Check if referencing a field with __attribute__((deprecated)).
+ if (DiagnoseUseOfDecl(IV, Loc))
+ return ExprError();
+
+ // FIXME: This should use a new expr for a direct reference, don't
+ // turn this into Self->ivar, just return a BareIVarExpr or something.
+ IdentifierInfo &II = Context.Idents.get("self");
+ UnqualifiedId SelfName;
+ SelfName.setIdentifier(&II, SourceLocation());
+ SelfName.setKind(UnqualifiedIdKind::IK_ImplicitSelfParam);
+ CXXScopeSpec SelfScopeSpec;
+ SourceLocation TemplateKWLoc;
+ ExprResult SelfExpr =
+ ActOnIdExpression(S, SelfScopeSpec, TemplateKWLoc, SelfName,
+ /*HasTrailingLParen=*/false,
+ /*IsAddressOfOperand=*/false);
+ if (SelfExpr.isInvalid())
+ return ExprError();
+
+ SelfExpr = DefaultLvalueConversion(SelfExpr.get());
+ if (SelfExpr.isInvalid())
+ return ExprError();
+
+ MarkAnyDeclReferenced(Loc, IV, true);
+
+ ObjCMethodFamily MF = CurMethod->getMethodFamily();
+ if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize &&
+ !IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV))
+ Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName();
+
+ ObjCIvarRefExpr *Result = new (Context)
+ ObjCIvarRefExpr(IV, IV->getUsageType(SelfExpr.get()->getType()), Loc,
+ IV->getLocation(), SelfExpr.get(), true, true);
+
+ if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
+ if (!isUnevaluatedContext() &&
+ !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
+ getCurFunction()->recordUseOfWeak(Result);
+ }
+ if (getLangOpts().ObjCAutoRefCount)
+ if (const BlockDecl *BD = CurContext->getInnermostBlockDecl())
+ ImplicitlyRetainedSelfLocs.push_back({Loc, BD});
+
+ return Result;
+}
+
+/// The parser has read a name in, and Sema has detected that we're currently
+/// inside an ObjC method. Perform some additional checks and determine if we
+/// should form a reference to an ivar. If so, build an expression referencing
+/// that ivar.
+ExprResult
+Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
+ IdentifierInfo *II, bool AllowBuiltinCreation) {
+ // FIXME: Integrate this lookup step into LookupParsedName.
+ DeclResult Ivar = LookupIvarInObjCMethod(Lookup, S, II);
+ if (Ivar.isInvalid())
+ return ExprError();
+ if (Ivar.isUsable())
+ return BuildIvarRefExpr(S, Lookup.getNameLoc(),
+ cast<ObjCIvarDecl>(Ivar.get()));
+
+ if (Lookup.empty() && II && AllowBuiltinCreation)
+ LookupBuiltin(Lookup);
+
// Sentinel value saying that we didn't do anything special.
- return ExprResult((Expr *)nullptr);
+ return ExprResult(false);
}
/// Cast a base object to a member's actual type.
@@ -3216,13 +3230,15 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
SmallString<32> RawChars;
ConvertUTF8ToWideString(Context.getTypeSizeInChars(ResTy).getQuantity(),
Str, RawChars);
- ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal,
+ ResTy = Context.getConstantArrayType(ResTy, LengthI, nullptr,
+ ArrayType::Normal,
/*IndexTypeQuals*/ 0);
SL = StringLiteral::Create(Context, RawChars, StringLiteral::Wide,
/*Pascal*/ false, ResTy, Loc);
} else {
ResTy = Context.adjustStringLiteralBaseType(Context.CharTy.withConst());
- ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal,
+ ResTy = Context.getConstantArrayType(ResTy, LengthI, nullptr,
+ ArrayType::Normal,
/*IndexTypeQuals*/ 0);
SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii,
/*Pascal*/ false, ResTy, Loc);
@@ -3462,7 +3478,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
unsigned Length = Literal.getUDSuffixOffset();
QualType StrTy = Context.getConstantArrayType(
Context.adjustStringLiteralBaseType(Context.CharTy.withConst()),
- llvm::APInt(32, Length + 1), ArrayType::Normal, 0);
+ llvm::APInt(32, Length + 1), nullptr, ArrayType::Normal, 0);
Expr *Lit = StringLiteral::Create(
Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii,
/*Pascal*/false, StrTy, &TokLoc, 1);
@@ -3808,6 +3824,16 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
QualType ExprTy = E->getType();
assert(!ExprTy->isReferenceType());
+ bool IsUnevaluatedOperand =
+ (ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf ||
+ ExprKind == UETT_PreferredAlignOf);
+ if (IsUnevaluatedOperand) {
+ ExprResult Result = CheckUnevaluatedOperand(E);
+ if (Result.isInvalid())
+ return true;
+ E = Result.get();
+ }
+
if (ExprKind == UETT_VecStep)
return CheckVecStepTraitOperandType(*this, ExprTy, E->getExprLoc(),
E->getSourceRange());
@@ -3845,9 +3871,8 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
// The operand for sizeof and alignof is in an unevaluated expression context,
// so side effects could result in unintended consequences.
- if ((ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf ||
- ExprKind == UETT_PreferredAlignOf) &&
- !inTemplateInstantiation() && E->HasSideEffects(Context, false))
+ if (IsUnevaluatedOperand && !inTemplateInstantiation() &&
+ E->HasSideEffects(Context, false))
Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context);
if (CheckObjCTraitOperandConstraints(*this, ExprTy, E->getExprLoc(),
@@ -3946,8 +3971,6 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
}
static bool CheckAlignOfExpr(Sema &S, Expr *E, UnaryExprOrTypeTrait ExprKind) {
- E = E->IgnoreParens();
-
// Cannot know anything else if the expression is dependent.
if (E->isTypeDependent())
return false;
@@ -3959,9 +3982,10 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, UnaryExprOrTypeTrait ExprKind) {
}
ValueDecl *D = nullptr;
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ Expr *Inner = E->IgnoreParens();
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Inner)) {
D = DRE->getDecl();
- } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Inner)) {
D = ME->getMemberDecl();
}
@@ -4026,7 +4050,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
#define NON_CANONICAL_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
T = QualType();
break;
// These types are never variably-modified.
@@ -4317,6 +4341,15 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
base = result.get();
}
+ // A comma-expression as the index is deprecated in C++2a onwards.
+ if (getLangOpts().CPlusPlus2a &&
+ ((isa<BinaryOperator>(idx) && cast<BinaryOperator>(idx)->isCommaOp()) ||
+ (isa<CXXOperatorCallExpr>(idx) &&
+ cast<CXXOperatorCallExpr>(idx)->getOperator() == OO_Comma))) {
+ Diag(idx->getExprLoc(), diag::warn_deprecated_comma_subscript)
+ << SourceRange(base->getBeginLoc(), rbLoc);
+ }
+
// Handle any non-overload placeholder types in the base and index
// expressions. We can't handle overloads here because the other
// operand might be an overloadable type, in which case the overload
@@ -4823,8 +4856,10 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
// default argument expression appears.
ContextRAII SavedContext(*this, FD);
LocalInstantiationScope Local(*this);
- Result = SubstInitializer(UninstExpr, MutiLevelArgList,
- /*DirectInit*/false);
+ runWithSufficientStackSpace(CallLoc, [&] {
+ Result = SubstInitializer(UninstExpr, MutiLevelArgList,
+ /*DirectInit*/false);
+ });
}
if (Result.isInvalid())
return true;
@@ -4935,7 +4970,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<FunctionCallCCC>(*this);
+ return std::make_unique<FunctionCallCCC>(*this);
}
private:
@@ -5296,6 +5331,11 @@ static bool isPlaceholderToRemoveAsArg(QualType type) {
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
case BuiltinType::Id:
#include "clang/Basic/OpenCLExtensionTypes.def"
+ // In practice we'll never use this, since all SVE types are sugared
+ // via TypedefTypes rather than exposed directly as BuiltinTypes.
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
#define PLACEHOLDER_TYPE(ID, SINGLETON_ID)
#define BUILTIN_TYPE(ID, SINGLETON_ID) case BuiltinType::ID:
#include "clang/AST/BuiltinTypes.def"
@@ -5366,8 +5406,8 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
QualType DeclType = FDecl->getType();
const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(DeclType);
- if (!Context.BuiltinInfo.hasPtrArgsOrResult(FDecl->getBuiltinID()) ||
- !FT || FT->isVariadic() || ArgExprs.size() != FT->getNumParams())
+ if (!Context.BuiltinInfo.hasPtrArgsOrResult(FDecl->getBuiltinID()) || !FT ||
+ ArgExprs.size() < FT->getNumParams())
return nullptr;
bool NeedsNewDecl = false;
@@ -5406,6 +5446,7 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
return nullptr;
FunctionProtoType::ExtProtoInfo EPI;
+ EPI.Variadic = FT->isVariadic();
QualType OverloadTy = Context.getFunctionType(FT->getReturnType(),
OverloadParams, EPI);
DeclContext *Parent = FDecl->getParent();
@@ -5883,7 +5924,9 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
<< FDecl << Fn->getSourceRange());
// CUDA: Kernel function must have 'void' return type
- if (!FuncT->getReturnType()->isVoidType())
+ if (!FuncT->getReturnType()->isVoidType() &&
+ !FuncT->getReturnType()->getAs<AutoType>() &&
+ !FuncT->getReturnType()->isInstantiationDependentType())
return ExprError(Diag(LParenLoc, diag::err_kern_type_not_void_return)
<< Fn->getType() << Fn->getSourceRange());
} else {
@@ -6103,6 +6146,77 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
ExprResult
Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
SourceLocation RBraceLoc) {
+ // Only produce each kind of designated initialization diagnostic once.
+ SourceLocation FirstDesignator;
+ bool DiagnosedArrayDesignator = false;
+ bool DiagnosedNestedDesignator = false;
+ bool DiagnosedMixedDesignator = false;
+
+ // Check that any designated initializers are syntactically valid in the
+ // current language mode.
+ for (unsigned I = 0, E = InitArgList.size(); I != E; ++I) {
+ if (auto *DIE = dyn_cast<DesignatedInitExpr>(InitArgList[I])) {
+ if (FirstDesignator.isInvalid())
+ FirstDesignator = DIE->getBeginLoc();
+
+ if (!getLangOpts().CPlusPlus)
+ break;
+
+ if (!DiagnosedNestedDesignator && DIE->size() > 1) {
+ DiagnosedNestedDesignator = true;
+ Diag(DIE->getBeginLoc(), diag::ext_designated_init_nested)
+ << DIE->getDesignatorsSourceRange();
+ }
+
+ for (auto &Desig : DIE->designators()) {
+ if (!Desig.isFieldDesignator() && !DiagnosedArrayDesignator) {
+ DiagnosedArrayDesignator = true;
+ Diag(Desig.getBeginLoc(), diag::ext_designated_init_array)
+ << Desig.getSourceRange();
+ }
+ }
+
+ if (!DiagnosedMixedDesignator &&
+ !isa<DesignatedInitExpr>(InitArgList[0])) {
+ DiagnosedMixedDesignator = true;
+ Diag(DIE->getBeginLoc(), diag::ext_designated_init_mixed)
+ << DIE->getSourceRange();
+ Diag(InitArgList[0]->getBeginLoc(), diag::note_designated_init_mixed)
+ << InitArgList[0]->getSourceRange();
+ }
+ } else if (getLangOpts().CPlusPlus && !DiagnosedMixedDesignator &&
+ isa<DesignatedInitExpr>(InitArgList[0])) {
+ DiagnosedMixedDesignator = true;
+ auto *DIE = cast<DesignatedInitExpr>(InitArgList[0]);
+ Diag(DIE->getBeginLoc(), diag::ext_designated_init_mixed)
+ << DIE->getSourceRange();
+ Diag(InitArgList[I]->getBeginLoc(), diag::note_designated_init_mixed)
+ << InitArgList[I]->getSourceRange();
+ }
+ }
+
+ if (FirstDesignator.isValid()) {
+ // Only diagnose designated initiaization as a C++20 extension if we didn't
+ // already diagnose use of (non-C++20) C99 designator syntax.
+ if (getLangOpts().CPlusPlus && !DiagnosedArrayDesignator &&
+ !DiagnosedNestedDesignator && !DiagnosedMixedDesignator) {
+ Diag(FirstDesignator, getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_designated_init
+ : diag::ext_cxx_designated_init);
+ } else if (!getLangOpts().CPlusPlus && !getLangOpts().C99) {
+ Diag(FirstDesignator, diag::ext_designated_init);
+ }
+ }
+
+ return BuildInitList(LBraceLoc, InitArgList, RBraceLoc);
+}
+
+ExprResult
+Sema::BuildInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
+ SourceLocation RBraceLoc) {
+ // Semantic analysis for initializers is done by ActOnDeclarator() and
+ // CheckInitializer() - it requires knowledge of the object being initialized.
+
// Immediately handle non-overload placeholders. Overloads can be
// resolved contextually, but everything else here can't.
for (unsigned I = 0, E = InitArgList.size(); I != E; ++I) {
@@ -6117,9 +6231,6 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList,
}
}
- // Semantic analysis for initializers is done by ActOnDeclarator() and
- // CheckInitializer() - it requires knowledge of the object being initialized.
-
InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitArgList,
RBraceLoc);
E->setType(Context.VoidTy); // FIXME: just a place holder for now.
@@ -6422,8 +6533,28 @@ bool Sema::areLaxCompatibleVectorTypes(QualType srcTy, QualType destTy) {
bool Sema::isLaxVectorConversion(QualType srcTy, QualType destTy) {
assert(destTy->isVectorType() || srcTy->isVectorType());
- if (!Context.getLangOpts().LaxVectorConversions)
+ switch (Context.getLangOpts().getLaxVectorConversions()) {
+ case LangOptions::LaxVectorConversionKind::None:
return false;
+
+ case LangOptions::LaxVectorConversionKind::Integer:
+ if (!srcTy->isIntegralOrEnumerationType()) {
+ auto *Vec = srcTy->getAs<VectorType>();
+ if (!Vec || !Vec->getElementType()->isIntegralOrEnumerationType())
+ return false;
+ }
+ if (!destTy->isIntegralOrEnumerationType()) {
+ auto *Vec = destTy->getAs<VectorType>();
+ if (!Vec || !Vec->getElementType()->isIntegralOrEnumerationType())
+ return false;
+ }
+ // OK, integer (vector) -> integer (vector) bitcast.
+ break;
+
+ case LangOptions::LaxVectorConversionKind::All:
+ break;
+ }
+
return areLaxCompatibleVectorTypes(srcTy, destTy);
}
@@ -6616,8 +6747,8 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
assert(Ty->isVectorType() && "Expected vector type");
SmallVector<Expr *, 8> initExprs;
- const VectorType *VTy = Ty->getAs<VectorType>();
- unsigned numElems = Ty->getAs<VectorType>()->getNumElements();
+ const VectorType *VTy = Ty->castAs<VectorType>();
+ unsigned numElems = VTy->getNumElements();
// '(...)' form of vector initialization in AltiVec: the number of
// initializers must be one or must match the size of the vector.
@@ -6628,7 +6759,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
// vector. If a single value is specified in the initializer then it will
// be replicated to all the components of the vector
if (numExprs == 1) {
- QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ QualType ElemTy = VTy->getElementType();
ExprResult Literal = DefaultLvalueConversion(exprs[0]);
if (Literal.isInvalid())
return ExprError();
@@ -6650,7 +6781,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
if (getLangOpts().OpenCL &&
VTy->getVectorKind() == VectorType::GenericVector &&
numExprs == 1) {
- QualType ElemTy = Ty->getAs<VectorType>()->getElementType();
+ QualType ElemTy = VTy->getElementType();
ExprResult Literal = DefaultLvalueConversion(exprs[0]);
if (Literal.isInvalid())
return ExprError();
@@ -6949,8 +7080,8 @@ checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS,
QualType RHSTy = RHS.get()->getType();
// get the "pointed to" types
- QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
- QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
+ QualType lhptee = LHSTy->castAs<PointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->castAs<PointerType>()->getPointeeType();
// ignore qualifiers on void (C99 6.5.15p3, clause 6)
if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) {
@@ -7400,9 +7531,10 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
compositeType = RHSOPT->isObjCBuiltinType() ? RHSTy : LHSTy;
} else if (Context.canAssignObjCInterfaces(RHSOPT, LHSOPT)) {
compositeType = LHSOPT->isObjCBuiltinType() ? LHSTy : RHSTy;
- } else if ((LHSTy->isObjCQualifiedIdType() ||
- RHSTy->isObjCQualifiedIdType()) &&
- Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) {
+ } else if ((LHSOPT->isObjCQualifiedIdType() ||
+ RHSOPT->isObjCQualifiedIdType()) &&
+ Context.ObjCQualifiedIdTypesAreCompatible(LHSOPT, RHSOPT,
+ true)) {
// Need to handle "id<xx>" explicitly.
// GCC allows qualified id and any Objective-C type to devolve to
// id. Currently localizing to here until clear this should be
@@ -7434,8 +7566,8 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
LHS = RHS = true;
return QualType();
}
- QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
- QualType rhptee = RHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType lhptee = LHSTy->castAs<PointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->castAs<ObjCObjectPointerType>()->getPointeeType();
QualType destPointee
= Context.getQualifiedType(lhptee, rhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
@@ -7454,8 +7586,8 @@ QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS,
LHS = RHS = true;
return QualType();
}
- QualType lhptee = LHSTy->getAs<ObjCObjectPointerType>()->getPointeeType();
- QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
+ QualType lhptee = LHSTy->castAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType rhptee = RHSTy->castAs<PointerType>()->getPointeeType();
QualType destPointee
= Context.getQualifiedType(rhptee, lhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
@@ -7488,7 +7620,12 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc,
static bool IsArithmeticOp(BinaryOperatorKind Opc) {
return BinaryOperator::isAdditiveOp(Opc) ||
BinaryOperator::isMultiplicativeOp(Opc) ||
- BinaryOperator::isShiftOp(Opc);
+ BinaryOperator::isShiftOp(Opc) || Opc == BO_And || Opc == BO_Or;
+ // This only checks for bitwise-or and bitwise-and, but not bitwise-xor and
+ // not any of the logical operators. Bitwise-xor is commonly used as a
+ // logical-xor because there is no logical-xor operator. The logical
+ // operators, including uses of xor, have a high false positive rate for
+ // precedence warnings.
}
/// IsArithmeticBinaryExpr - Returns true if E is an arithmetic binary
@@ -7578,7 +7715,11 @@ static void DiagnoseConditionalPrecedence(Sema &Self,
// The condition is an arithmetic binary expression, with a right-
// hand side that looks boolean, so warn.
- Self.Diag(OpLoc, diag::warn_precedence_conditional)
+ unsigned DiagID = BinaryOperator::isBitwiseOp(CondOpcode)
+ ? diag::warn_precedence_bitwise_conditional
+ : diag::warn_precedence_conditional;
+
+ Self.Diag(OpLoc, DiagID)
<< Condition->getSourceRange()
<< BinaryOperator::getOpcodeStr(CondOpcode);
@@ -7960,8 +8101,8 @@ checkObjCPointerTypesForAssignment(Sema &S, QualType LHSType,
return Sema::IncompatiblePointer;
return Sema::Compatible;
}
- QualType lhptee = LHSType->getAs<ObjCObjectPointerType>()->getPointeeType();
- QualType rhptee = RHSType->getAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType lhptee = LHSType->castAs<ObjCObjectPointerType>()->getPointeeType();
+ QualType rhptee = RHSType->castAs<ObjCObjectPointerType>()->getPointeeType();
if (!lhptee.isAtLeastAsQualifiedAs(rhptee) &&
// make an exception for id<P>
@@ -9063,7 +9204,7 @@ static void checkArithmeticNull(Sema &S, ExprResult &LHS, ExprResult &RHS,
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
}
-static void DiagnoseDivisionSizeofPointer(Sema &S, Expr *LHS, Expr *RHS,
+static void DiagnoseDivisionSizeofPointerOrArray(Sema &S, Expr *LHS, Expr *RHS,
SourceLocation Loc) {
const auto *LUE = dyn_cast<UnaryExprOrTypeTraitExpr>(LHS);
const auto *RUE = dyn_cast<UnaryExprOrTypeTraitExpr>(RHS);
@@ -9073,7 +9214,8 @@ static void DiagnoseDivisionSizeofPointer(Sema &S, Expr *LHS, Expr *RHS,
RUE->getKind() != UETT_SizeOf)
return;
- QualType LHSTy = LUE->getArgumentExpr()->IgnoreParens()->getType();
+ const Expr *LHSArg = LUE->getArgumentExpr()->IgnoreParens();
+ QualType LHSTy = LHSArg->getType();
QualType RHSTy;
if (RUE->isArgumentType())
@@ -9081,12 +9223,33 @@ static void DiagnoseDivisionSizeofPointer(Sema &S, Expr *LHS, Expr *RHS,
else
RHSTy = RUE->getArgumentExpr()->IgnoreParens()->getType();
- if (!LHSTy->isPointerType() || RHSTy->isPointerType())
- return;
- if (LHSTy->getPointeeType() != RHSTy)
- return;
+ if (LHSTy->isPointerType() && !RHSTy->isPointerType()) {
+ if (!S.Context.hasSameUnqualifiedType(LHSTy->getPointeeType(), RHSTy))
+ return;
- S.Diag(Loc, diag::warn_division_sizeof_ptr) << LHS << LHS->getSourceRange();
+ S.Diag(Loc, diag::warn_division_sizeof_ptr) << LHS << LHS->getSourceRange();
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(LHSArg)) {
+ if (const ValueDecl *LHSArgDecl = DRE->getDecl())
+ S.Diag(LHSArgDecl->getLocation(), diag::note_pointer_declared_here)
+ << LHSArgDecl;
+ }
+ } else if (const auto *ArrayTy = S.Context.getAsArrayType(LHSTy)) {
+ QualType ArrayElemTy = ArrayTy->getElementType();
+ if (ArrayElemTy != S.Context.getBaseElementType(ArrayTy) ||
+ ArrayElemTy->isDependentType() || RHSTy->isDependentType() ||
+ ArrayElemTy->isCharType() ||
+ S.Context.getTypeSize(ArrayElemTy) == S.Context.getTypeSize(RHSTy))
+ return;
+ S.Diag(Loc, diag::warn_division_sizeof_array)
+ << LHSArg->getSourceRange() << ArrayElemTy << RHSTy;
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(LHSArg)) {
+ if (const ValueDecl *LHSArgDecl = DRE->getDecl())
+ S.Diag(LHSArgDecl->getLocation(), diag::note_array_declared_here)
+ << LHSArgDecl;
+ }
+
+ S.Diag(Loc, diag::note_precedence_silence) << RHS;
+ }
}
static void DiagnoseBadDivideOrRemainderValues(Sema& S, ExprResult &LHS,
@@ -9122,7 +9285,7 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
return InvalidOperands(Loc, LHS, RHS);
if (IsDiv) {
DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, IsDiv);
- DiagnoseDivisionSizeofPointer(*this, LHS.get(), RHS.get(), Loc);
+ DiagnoseDivisionSizeofPointerOrArray(*this, LHS.get(), RHS.get(), Loc);
}
return compType;
}
@@ -9281,8 +9444,8 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
// if both are pointers check if operation is valid wrt address spaces
if (S.getLangOpts().OpenCL && isLHSPointer && isRHSPointer) {
- const PointerType *lhsPtr = LHSExpr->getType()->getAs<PointerType>();
- const PointerType *rhsPtr = RHSExpr->getType()->getAs<PointerType>();
+ const PointerType *lhsPtr = LHSExpr->getType()->castAs<PointerType>();
+ const PointerType *rhsPtr = RHSExpr->getType()->castAs<PointerType>();
if (!lhsPtr->isAddressSpaceOverlapping(*rhsPtr)) {
S.Diag(Loc,
diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
@@ -9914,8 +10077,8 @@ static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc,
QualType T = S.FindCompositePointerType(Loc, LHS, RHS);
if (T.isNull()) {
- if ((LHSType->isPointerType() || LHSType->isMemberPointerType()) &&
- (RHSType->isPointerType() || RHSType->isMemberPointerType()))
+ if ((LHSType->isAnyPointerType() || LHSType->isMemberPointerType()) &&
+ (RHSType->isAnyPointerType() || RHSType->isMemberPointerType()))
diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true);
else
S.InvalidOperands(Loc, LHS, RHS);
@@ -10129,20 +10292,18 @@ static void diagnoseLogicalNotOnLHSofCheck(Sema &S, ExprResult &LHS,
<< FixItHint::CreateInsertion(SecondClose, ")");
}
-// Get the decl for a simple expression: a reference to a variable,
-// an implicit C++ field reference, or an implicit ObjC ivar reference.
-static ValueDecl *getCompareDecl(Expr *E) {
- if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
- return DR->getDecl();
- if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E)) {
- if (Ivar->isFreeIvar())
- return Ivar->getDecl();
- }
- if (MemberExpr *Mem = dyn_cast<MemberExpr>(E)) {
+// Returns true if E refers to a non-weak array.
+static bool checkForArray(const Expr *E) {
+ const ValueDecl *D = nullptr;
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) {
+ D = DR->getDecl();
+ } else if (const MemberExpr *Mem = dyn_cast<MemberExpr>(E)) {
if (Mem->isImplicitAccess())
- return Mem->getMemberDecl();
+ D = Mem->getMemberDecl();
}
- return nullptr;
+ if (!D)
+ return false;
+ return D->getType()->isArrayType() && !D->isWeak();
}
/// Diagnose some forms of syntactically-obvious tautological comparison.
@@ -10175,47 +10336,54 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
// obvious cases in the definition of the template anyways. The idea is to
// warn when the typed comparison operator will always evaluate to the same
// result.
- ValueDecl *DL = getCompareDecl(LHSStripped);
- ValueDecl *DR = getCompareDecl(RHSStripped);
- if (DL && DR && declaresSameEntity(DL, DR)) {
- StringRef Result;
+
+ // Used for indexing into %select in warn_comparison_always
+ enum {
+ AlwaysConstant,
+ AlwaysTrue,
+ AlwaysFalse,
+ AlwaysEqual, // std::strong_ordering::equal from operator<=>
+ };
+
+ if (Expr::isSameComparisonOperand(LHS, RHS)) {
+ unsigned Result;
switch (Opc) {
case BO_EQ: case BO_LE: case BO_GE:
- Result = "true";
+ Result = AlwaysTrue;
break;
case BO_NE: case BO_LT: case BO_GT:
- Result = "false";
+ Result = AlwaysFalse;
break;
case BO_Cmp:
- Result = "'std::strong_ordering::equal'";
+ Result = AlwaysEqual;
break;
default:
+ Result = AlwaysConstant;
break;
}
S.DiagRuntimeBehavior(Loc, nullptr,
S.PDiag(diag::warn_comparison_always)
- << 0 /*self-comparison*/ << !Result.empty()
+ << 0 /*self-comparison*/
<< Result);
- } else if (DL && DR &&
- DL->getType()->isArrayType() && DR->getType()->isArrayType() &&
- !DL->isWeak() && !DR->isWeak()) {
+ } else if (checkForArray(LHSStripped) && checkForArray(RHSStripped)) {
// What is it always going to evaluate to?
- StringRef Result;
+ unsigned Result;
switch(Opc) {
case BO_EQ: // e.g. array1 == array2
- Result = "false";
+ Result = AlwaysFalse;
break;
case BO_NE: // e.g. array1 != array2
- Result = "true";
+ Result = AlwaysTrue;
break;
default: // e.g. array1 <= array2
// The best we can say is 'a constant'
+ Result = AlwaysConstant;
break;
}
S.DiagRuntimeBehavior(Loc, nullptr,
S.PDiag(diag::warn_comparison_always)
<< 1 /*array comparison*/
- << !Result.empty() << Result);
+ << Result);
}
if (isa<CastExpr>(LHSStripped))
@@ -10370,7 +10538,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S,
return QualType();
}
QualType IntType =
- LHSStrippedType->getAs<EnumType>()->getDecl()->getIntegerType();
+ LHSStrippedType->castAs<EnumType>()->getDecl()->getIntegerType();
assert(IntType->isArithmeticType());
// We can't use `CK_IntegralCast` when the underlying type is 'bool', so we
@@ -10446,6 +10614,32 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
return S.Context.getLogicalOperationType();
}
+void Sema::CheckPtrComparisonWithNullChar(ExprResult &E, ExprResult &NullE) {
+ if (!NullE.get()->getType()->isAnyPointerType())
+ return;
+ int NullValue = PP.isMacroDefined("NULL") ? 0 : 1;
+ if (!E.get()->getType()->isAnyPointerType() &&
+ E.get()->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNotNull) ==
+ Expr::NPCK_ZeroExpression) {
+ if (const auto *CL = dyn_cast<CharacterLiteral>(E.get())) {
+ if (CL->getValue() == 0)
+ Diag(E.get()->getExprLoc(), diag::warn_pointer_compare)
+ << NullValue
+ << FixItHint::CreateReplacement(E.get()->getExprLoc(),
+ NullValue ? "NULL" : "(void *)0");
+ } else if (const auto *CE = dyn_cast<CStyleCastExpr>(E.get())) {
+ TypeSourceInfo *TI = CE->getTypeInfoAsWritten();
+ QualType T = Context.getCanonicalType(TI->getType()).getUnqualifiedType();
+ if (T == Context.CharTy)
+ Diag(E.get()->getExprLoc(), diag::warn_pointer_compare)
+ << NullValue
+ << FixItHint::CreateReplacement(E.get()->getExprLoc(),
+ NullValue ? "NULL" : "(void *)0");
+ }
+ }
+}
+
// C99 6.5.8, C++ [expr.rel]
QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
@@ -10479,6 +10673,10 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
}
checkArithmeticNull(*this, LHS, RHS, Loc, /*IsCompare=*/true);
+ if (!getLangOpts().CPlusPlus && BinaryOperator::isEqualityOp(Opc)) {
+ CheckPtrComparisonWithNullChar(LHS, RHS);
+ CheckPtrComparisonWithNullChar(RHS, LHS);
+ }
// Handle vector comparisons separately.
if (LHS.get()->getType()->isVectorType() ||
@@ -10623,8 +10821,8 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
if (LCanPointeeTy != RCanPointeeTy) {
// Treat NULL constant as a special case in OpenCL.
if (getLangOpts().OpenCL && !LHSIsNull && !RHSIsNull) {
- const PointerType *LHSPtr = LHSType->getAs<PointerType>();
- if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->getAs<PointerType>())) {
+ const PointerType *LHSPtr = LHSType->castAs<PointerType>();
+ if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->castAs<PointerType>())) {
Diag(Loc,
diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
<< LHSType << RHSType << 0 /* comparison */
@@ -10889,7 +11087,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
// the largest type to the smallest type to avoid cases where long long == long,
// where long gets picked over long long.
QualType Sema::GetSignedVectorType(QualType V) {
- const VectorType *VTy = V->getAs<VectorType>();
+ const VectorType *VTy = V->castAs<VectorType>();
unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
if (isa<ExtVectorType>(VTy)) {
@@ -10944,7 +11142,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
// If AltiVec, the comparison results in a numeric type, i.e.
// bool for C++, int for C
if (getLangOpts().AltiVec &&
- vType->getAs<VectorType>()->getVectorKind() == VectorType::AltiVecVector)
+ vType->castAs<VectorType>()->getVectorKind() == VectorType::AltiVecVector)
return Context.getLogicalOperationType();
// For non-floating point types, check for self-comparisons of the form
@@ -10963,6 +11161,120 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
return GetSignedVectorType(vType);
}
+static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS,
+ const ExprResult &XorRHS,
+ const SourceLocation Loc) {
+ // Do not diagnose macros.
+ if (Loc.isMacroID())
+ return;
+
+ bool Negative = false;
+ bool ExplicitPlus = false;
+ const auto *LHSInt = dyn_cast<IntegerLiteral>(XorLHS.get());
+ const auto *RHSInt = dyn_cast<IntegerLiteral>(XorRHS.get());
+
+ if (!LHSInt)
+ return;
+ if (!RHSInt) {
+ // Check negative literals.
+ if (const auto *UO = dyn_cast<UnaryOperator>(XorRHS.get())) {
+ UnaryOperatorKind Opc = UO->getOpcode();
+ if (Opc != UO_Minus && Opc != UO_Plus)
+ return;
+ RHSInt = dyn_cast<IntegerLiteral>(UO->getSubExpr());
+ if (!RHSInt)
+ return;
+ Negative = (Opc == UO_Minus);
+ ExplicitPlus = !Negative;
+ } else {
+ return;
+ }
+ }
+
+ const llvm::APInt &LeftSideValue = LHSInt->getValue();
+ llvm::APInt RightSideValue = RHSInt->getValue();
+ if (LeftSideValue != 2 && LeftSideValue != 10)
+ return;
+
+ if (LeftSideValue.getBitWidth() != RightSideValue.getBitWidth())
+ return;
+
+ CharSourceRange ExprRange = CharSourceRange::getCharRange(
+ LHSInt->getBeginLoc(), S.getLocForEndOfToken(RHSInt->getLocation()));
+ llvm::StringRef ExprStr =
+ Lexer::getSourceText(ExprRange, S.getSourceManager(), S.getLangOpts());
+
+ CharSourceRange XorRange =
+ CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc));
+ llvm::StringRef XorStr =
+ Lexer::getSourceText(XorRange, S.getSourceManager(), S.getLangOpts());
+ // Do not diagnose if xor keyword/macro is used.
+ if (XorStr == "xor")
+ return;
+
+ std::string LHSStr = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(LHSInt->getSourceRange()),
+ S.getSourceManager(), S.getLangOpts());
+ std::string RHSStr = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(RHSInt->getSourceRange()),
+ S.getSourceManager(), S.getLangOpts());
+
+ if (Negative) {
+ RightSideValue = -RightSideValue;
+ RHSStr = "-" + RHSStr;
+ } else if (ExplicitPlus) {
+ RHSStr = "+" + RHSStr;
+ }
+
+ StringRef LHSStrRef = LHSStr;
+ StringRef RHSStrRef = RHSStr;
+ // Do not diagnose literals with digit separators, binary, hexadecimal, octal
+ // literals.
+ if (LHSStrRef.startswith("0b") || LHSStrRef.startswith("0B") ||
+ RHSStrRef.startswith("0b") || RHSStrRef.startswith("0B") ||
+ LHSStrRef.startswith("0x") || LHSStrRef.startswith("0X") ||
+ RHSStrRef.startswith("0x") || RHSStrRef.startswith("0X") ||
+ (LHSStrRef.size() > 1 && LHSStrRef.startswith("0")) ||
+ (RHSStrRef.size() > 1 && RHSStrRef.startswith("0")) ||
+ LHSStrRef.find('\'') != StringRef::npos ||
+ RHSStrRef.find('\'') != StringRef::npos)
+ return;
+
+ bool SuggestXor = S.getLangOpts().CPlusPlus || S.getPreprocessor().isMacroDefined("xor");
+ const llvm::APInt XorValue = LeftSideValue ^ RightSideValue;
+ int64_t RightSideIntValue = RightSideValue.getSExtValue();
+ if (LeftSideValue == 2 && RightSideIntValue >= 0) {
+ std::string SuggestedExpr = "1 << " + RHSStr;
+ bool Overflow = false;
+ llvm::APInt One = (LeftSideValue - 1);
+ llvm::APInt PowValue = One.sshl_ov(RightSideValue, Overflow);
+ if (Overflow) {
+ if (RightSideIntValue < 64)
+ S.Diag(Loc, diag::warn_xor_used_as_pow_base)
+ << ExprStr << XorValue.toString(10, true) << ("1LL << " + RHSStr)
+ << FixItHint::CreateReplacement(ExprRange, "1LL << " + RHSStr);
+ else if (RightSideIntValue == 64)
+ S.Diag(Loc, diag::warn_xor_used_as_pow) << ExprStr << XorValue.toString(10, true);
+ else
+ return;
+ } else {
+ S.Diag(Loc, diag::warn_xor_used_as_pow_base_extra)
+ << ExprStr << XorValue.toString(10, true) << SuggestedExpr
+ << PowValue.toString(10, true)
+ << FixItHint::CreateReplacement(
+ ExprRange, (RightSideIntValue == 0) ? "1" : SuggestedExpr);
+ }
+
+ S.Diag(Loc, diag::note_xor_used_as_pow_silence) << ("0x2 ^ " + RHSStr) << SuggestXor;
+ } else if (LeftSideValue == 10) {
+ std::string SuggestedValue = "1e" + std::to_string(RightSideIntValue);
+ S.Diag(Loc, diag::warn_xor_used_as_pow_base)
+ << ExprStr << XorValue.toString(10, true) << SuggestedValue
+ << FixItHint::CreateReplacement(ExprRange, SuggestedValue);
+ S.Diag(Loc, diag::note_xor_used_as_pow_silence) << ("0xA ^ " + RHSStr) << SuggestXor;
+ }
+}
+
QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc) {
// Ensure that either both operands are of the same vector type, or
@@ -11014,6 +11326,9 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS,
LHS = LHSResult.get();
RHS = RHSResult.get();
+ if (Opc == BO_Xor)
+ diagnoseXorMisusedAsPow(*this, LHS, RHS, Loc);
+
if (!compType.isNull() && compType->isIntegralOrUnscopedEnumerationType())
return compType;
return InvalidOperands(Loc, LHS, RHS);
@@ -11027,10 +11342,22 @@ inline QualType Sema::CheckLogicalOperands(ExprResult &LHS, ExprResult &RHS,
if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType())
return CheckVectorLogicalOperands(LHS, RHS, Loc);
+ bool EnumConstantInBoolContext = false;
+ for (const ExprResult &HS : {LHS, RHS}) {
+ if (const auto *DREHS = dyn_cast<DeclRefExpr>(HS.get())) {
+ const auto *ECDHS = dyn_cast<EnumConstantDecl>(DREHS->getDecl());
+ if (ECDHS && ECDHS->getInitVal() != 0 && ECDHS->getInitVal() != 1)
+ EnumConstantInBoolContext = true;
+ }
+ }
+
+ if (EnumConstantInBoolContext)
+ Diag(Loc, diag::warn_enum_constant_in_bool_context);
+
// 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.
- if (LHS.get()->getType()->isIntegerType() &&
+ if (!EnumConstantInBoolContext && LHS.get()->getType()->isIntegerType() &&
!LHS.get()->getType()->isBooleanType() &&
RHS.get()->getType()->isIntegerType() && !RHS.get()->isValueDependent() &&
// Don't warn in macros or template instantiations.
@@ -11651,6 +11978,21 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
CheckForNullPointerDereference(*this, LHSExpr);
+ if (getLangOpts().CPlusPlus2a && LHSType.isVolatileQualified()) {
+ if (CompoundType.isNull()) {
+ // C++2a [expr.ass]p5:
+ // A simple-assignment whose left operand is of a volatile-qualified
+ // type is deprecated unless the assignment is either a discarded-value
+ // expression or an unevaluated operand
+ ExprEvalContexts.back().VolatileAssignmentLHSs.push_back(LHSExpr);
+ } else {
+ // C++2a [expr.ass]p6:
+ // [Compound-assignment] expressions are deprecated if E1 has
+ // volatile-qualified type
+ Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType;
+ }
+ }
+
// C99 6.5.16p3: The type of an assignment expression is the type of the
// left operand unless the left operand has qualified type, in which case
// it is the unqualified version of the type of the left operand.
@@ -11824,11 +12166,11 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
} else if (S.getLangOpts().AltiVec && ResType->isVectorType()) {
// OK! ( C/C++ Language Extensions for CBEA(Version 2.6) 10.3 )
} else if (S.getLangOpts().ZVector && ResType->isVectorType() &&
- (ResType->getAs<VectorType>()->getVectorKind() !=
+ (ResType->castAs<VectorType>()->getVectorKind() !=
VectorType::AltiVecBool)) {
// The z vector extensions allow ++ and -- for non-bool vectors.
} else if(S.getLangOpts().OpenCL && ResType->isVectorType() &&
- ResType->getAs<VectorType>()->getElementType()->isIntegerType()) {
+ ResType->castAs<VectorType>()->getElementType()->isIntegerType()) {
// OpenCL V1.2 6.3 says dec/inc ops operate on integer vector types.
} else {
S.Diag(OpLoc, diag::err_typecheck_illegal_increment_decrement)
@@ -11839,6 +12181,12 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
// Now make sure the operand is a modifiable lvalue.
if (CheckForModifiableLvalue(Op, OpLoc, S))
return QualType();
+ if (S.getLangOpts().CPlusPlus2a && ResType.isVolatileQualified()) {
+ // C++2a [expr.pre.inc]p1, [expr.post.inc]p1:
+ // An operand with volatile-qualified type is deprecated
+ S.Diag(OpLoc, diag::warn_deprecated_increment_decrement_volatile)
+ << IsInc << ResType;
+ }
// 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.
@@ -12414,7 +12762,7 @@ static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS,
LHS = convertVector(LHS.get(), Context.FloatTy, S);
auto *BO = new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, BinOpResTy,
VK, OK, OpLoc, FPFeatures);
- return convertVector(BO, ResultTy->getAs<VectorType>()->getElementType(), S);
+ return convertVector(BO, ResultTy->castAs<VectorType>()->getElementType(), S);
}
static std::pair<ExprResult, ExprResult>
@@ -12971,6 +13319,13 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,
S.LookupOverloadedOperatorName(OverOp, Sc, LHS->getType(),
RHS->getType(), Functions);
+ // In C++20 onwards, we may have a second operator to look up.
+ if (S.getLangOpts().CPlusPlus2a) {
+ if (OverloadedOperatorKind ExtraOp = getRewrittenOverloadedOperator(OverOp))
+ S.LookupOverloadedOperatorName(ExtraOp, Sc, LHS->getType(),
+ RHS->getType(), Functions);
+ }
+
// Build the (potentially-overloaded, potentially-dependent)
// binary operation.
return S.CreateOverloadedBinOp(OpLoc, Opc, Functions, LHS, RHS);
@@ -13170,7 +13525,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
else if (resultType->isVectorType() &&
// The z vector extensions don't allow + or - with bool vectors.
(!Context.getLangOpts().ZVector ||
- resultType->getAs<VectorType>()->getVectorKind() !=
+ resultType->castAs<VectorType>()->getVectorKind() !=
VectorType::AltiVecBool))
break;
else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6
@@ -13186,7 +13541,6 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
if (Input.isInvalid())
return ExprError();
resultType = Input.get()->getType();
-
if (resultType->isDependentType())
break;
// C99 6.5.3.3p1. We allow complex int and float as a GCC extension.
@@ -13199,7 +13553,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) {
// OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
// on vector float types.
- QualType T = resultType->getAs<ExtVectorType>()->getElementType();
+ QualType T = resultType->castAs<ExtVectorType>()->getElementType();
if (!T->isIntegerType())
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
@@ -13244,7 +13598,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
!Context.getLangOpts().OpenCLCPlusPlus) {
// OpenCL v1.1 6.3.h: The logical operator not (!) does not
// operate on vector float types.
- QualType T = resultType->getAs<ExtVectorType>()->getElementType();
+ QualType T = resultType->castAs<ExtVectorType>()->getElementType();
if (!T->isIntegerType())
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< resultType << Input.get()->getSourceRange());
@@ -13728,10 +14082,11 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) {
BlockDecl *Block = BlockDecl::Create(Context, CurContext, CaretLoc);
if (LangOpts.CPlusPlus) {
+ MangleNumberingContext *MCtx;
Decl *ManglingContextDecl;
- if (MangleNumberingContext *MCtx =
- getCurrentMangleNumberContext(Block->getDeclContext(),
- ManglingContextDecl)) {
+ std::tie(MCtx, ManglingContextDecl) =
+ getCurrentMangleNumberContext(Block->getDeclContext());
+ if (MCtx) {
unsigned ManglingNumber = MCtx->getManglingNumber(Block);
Block->setBlockMangling(ManglingNumber, ManglingContextDecl);
}
@@ -13909,7 +14264,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// If the user wrote a function type in some form, try to use that.
if (!BSI->FunctionType.isNull()) {
- const FunctionType *FTy = BSI->FunctionType->getAs<FunctionType>();
+ const FunctionType *FTy = BSI->FunctionType->castAs<FunctionType>();
FunctionType::ExtInfo Ext = FTy->getExtInfo();
if (NoReturn && !Ext.getNoReturn()) Ext = Ext.withNoReturn(true);
@@ -14381,24 +14736,24 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
case IncompatibleObjCQualifiedId: {
if (SrcType->isObjCQualifiedIdType()) {
const ObjCObjectPointerType *srcOPT =
- SrcType->getAs<ObjCObjectPointerType>();
+ SrcType->castAs<ObjCObjectPointerType>();
for (auto *srcProto : srcOPT->quals()) {
PDecl = srcProto;
break;
}
if (const ObjCInterfaceType *IFaceT =
- DstType->getAs<ObjCObjectPointerType>()->getInterfaceType())
+ DstType->castAs<ObjCObjectPointerType>()->getInterfaceType())
IFace = IFaceT->getDecl();
}
else if (DstType->isObjCQualifiedIdType()) {
const ObjCObjectPointerType *dstOPT =
- DstType->getAs<ObjCObjectPointerType>();
+ DstType->castAs<ObjCObjectPointerType>();
for (auto *dstProto : dstOPT->quals()) {
PDecl = dstProto;
break;
}
if (const ObjCInterfaceType *IFaceT =
- SrcType->getAs<ObjCObjectPointerType>()->getInterfaceType())
+ SrcType->castAs<ObjCObjectPointerType>()->getInterfaceType())
IFace = IFaceT->getDecl();
}
DiagKind = diag::warn_incompatible_qualified_id;
@@ -14775,6 +15130,26 @@ void Sema::WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec) {
Rec.PossibleDerefs.clear();
}
+/// Check whether E, which is either a discarded-value expression or an
+/// unevaluated operand, is a simple-assignment to a volatlie-qualified lvalue,
+/// and if so, remove it from the list of volatile-qualified assignments that
+/// we are going to warn are deprecated.
+void Sema::CheckUnusedVolatileAssignment(Expr *E) {
+ if (!E->getType().isVolatileQualified() || !getLangOpts().CPlusPlus2a)
+ return;
+
+ // Note: ignoring parens here is not justified by the standard rules, but
+ // ignoring parentheses seems like a more reasonable approach, and this only
+ // drives a deprecation warning so doesn't affect conformance.
+ if (auto *BO = dyn_cast<BinaryOperator>(E->IgnoreParenImpCasts())) {
+ if (BO->getOpcode() == BO_Assign) {
+ auto &LHSs = ExprEvalContexts.back().VolatileAssignmentLHSs;
+ LHSs.erase(std::remove(LHSs.begin(), LHSs.end(), BO->getLHS()),
+ LHSs.end());
+ }
+ }
+}
+
void Sema::PopExpressionEvaluationContext() {
ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back();
unsigned NumTypos = Rec.NumTypos;
@@ -14809,6 +15184,13 @@ void Sema::PopExpressionEvaluationContext() {
WarnOnPendingNoDerefs(Rec);
+ // Warn on any volatile-qualified simple-assignments that are not discarded-
+ // value expressions nor unevaluated operands (those cases get removed from
+ // this list by CheckUnusedVolatileAssignment).
+ for (auto *BO : Rec.VolatileAssignmentLHSs)
+ Diag(BO->getBeginLoc(), diag::warn_deprecated_simple_assign_volatile)
+ << BO->getType();
+
// When are coming out of an unevaluated context, clear out any
// temporaries that we may have created as part of the evaluation of
// the expression in that context: they aren't relevant because they
@@ -15032,6 +15414,17 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
if (IsRecursiveCall && OdrUse == OdrUseContext::Used)
OdrUse = OdrUseContext::FormallyOdrUsed;
+ // Trivial default constructors and destructors are never actually used.
+ // FIXME: What about other special members?
+ if (Func->isTrivial() && !Func->hasAttr<DLLExportAttr>() &&
+ OdrUse == OdrUseContext::Used) {
+ if (auto *Constructor = dyn_cast<CXXConstructorDecl>(Func))
+ if (Constructor->isDefaultConstructor())
+ OdrUse = OdrUseContext::FormallyOdrUsed;
+ if (isa<CXXDestructorDecl>(Func))
+ OdrUse = OdrUseContext::FormallyOdrUsed;
+ }
+
// C++20 [expr.const]p12:
// A function [...] is needed for constant evaluation if it is [...] a
// constexpr function that is named by an expression that is potentially
@@ -15092,98 +15485,101 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
// If we need a definition, try to create one.
if (NeedDefinition && !Func->getBody()) {
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
- Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl());
- if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
- if (Constructor->isDefaultConstructor()) {
- if (Constructor->isTrivial() &&
- !Constructor->hasAttr<DLLExportAttr>())
+ runWithSufficientStackSpace(Loc, [&] {
+ if (CXXConstructorDecl *Constructor =
+ dyn_cast<CXXConstructorDecl>(Func)) {
+ Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl());
+ if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
+ if (Constructor->isDefaultConstructor()) {
+ if (Constructor->isTrivial() &&
+ !Constructor->hasAttr<DLLExportAttr>())
+ return;
+ DefineImplicitDefaultConstructor(Loc, Constructor);
+ } else if (Constructor->isCopyConstructor()) {
+ DefineImplicitCopyConstructor(Loc, Constructor);
+ } else if (Constructor->isMoveConstructor()) {
+ DefineImplicitMoveConstructor(Loc, Constructor);
+ }
+ } else if (Constructor->getInheritedConstructor()) {
+ DefineInheritingConstructor(Loc, Constructor);
+ }
+ } else if (CXXDestructorDecl *Destructor =
+ dyn_cast<CXXDestructorDecl>(Func)) {
+ Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
+ if (Destructor->isDefaulted() && !Destructor->isDeleted()) {
+ if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>())
return;
- DefineImplicitDefaultConstructor(Loc, Constructor);
- } else if (Constructor->isCopyConstructor()) {
- DefineImplicitCopyConstructor(Loc, Constructor);
- } else if (Constructor->isMoveConstructor()) {
- DefineImplicitMoveConstructor(Loc, Constructor);
+ DefineImplicitDestructor(Loc, Destructor);
}
- } else if (Constructor->getInheritedConstructor()) {
- DefineInheritingConstructor(Loc, Constructor);
- }
- } else if (CXXDestructorDecl *Destructor =
- dyn_cast<CXXDestructorDecl>(Func)) {
- Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
- if (Destructor->isDefaulted() && !Destructor->isDeleted()) {
- if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>())
- return;
- DefineImplicitDestructor(Loc, Destructor);
+ if (Destructor->isVirtual() && getLangOpts().AppleKext)
+ MarkVTableUsed(Loc, Destructor->getParent());
+ } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
+ if (MethodDecl->isOverloadedOperator() &&
+ MethodDecl->getOverloadedOperator() == OO_Equal) {
+ MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl());
+ if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) {
+ if (MethodDecl->isCopyAssignmentOperator())
+ DefineImplicitCopyAssignment(Loc, MethodDecl);
+ else if (MethodDecl->isMoveAssignmentOperator())
+ DefineImplicitMoveAssignment(Loc, MethodDecl);
+ }
+ } else if (isa<CXXConversionDecl>(MethodDecl) &&
+ MethodDecl->getParent()->isLambda()) {
+ CXXConversionDecl *Conversion =
+ cast<CXXConversionDecl>(MethodDecl->getFirstDecl());
+ if (Conversion->isLambdaToBlockPointerConversion())
+ DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
+ else
+ DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion);
+ } else if (MethodDecl->isVirtual() && getLangOpts().AppleKext)
+ MarkVTableUsed(Loc, MethodDecl->getParent());
}
- if (Destructor->isVirtual() && getLangOpts().AppleKext)
- MarkVTableUsed(Loc, Destructor->getParent());
- } else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
- if (MethodDecl->isOverloadedOperator() &&
- MethodDecl->getOverloadedOperator() == OO_Equal) {
- MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl());
- if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) {
- if (MethodDecl->isCopyAssignmentOperator())
- DefineImplicitCopyAssignment(Loc, MethodDecl);
- else if (MethodDecl->isMoveAssignmentOperator())
- DefineImplicitMoveAssignment(Loc, MethodDecl);
- }
- } else if (isa<CXXConversionDecl>(MethodDecl) &&
- MethodDecl->getParent()->isLambda()) {
- CXXConversionDecl *Conversion =
- cast<CXXConversionDecl>(MethodDecl->getFirstDecl());
- if (Conversion->isLambdaToBlockPointerConversion())
- DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
- else
- DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion);
- } else if (MethodDecl->isVirtual() && getLangOpts().AppleKext)
- MarkVTableUsed(Loc, MethodDecl->getParent());
- }
- // Implicit instantiation of function templates and member functions of
- // class templates.
- if (Func->isImplicitlyInstantiable()) {
- TemplateSpecializationKind TSK =
- Func->getTemplateSpecializationKindForInstantiation();
- SourceLocation PointOfInstantiation = Func->getPointOfInstantiation();
- bool FirstInstantiation = PointOfInstantiation.isInvalid();
- if (FirstInstantiation) {
- PointOfInstantiation = Loc;
- Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
- } else if (TSK != TSK_ImplicitInstantiation) {
- // Use the point of use as the point of instantiation, instead of the
- // point of explicit instantiation (which we track as the actual point
- // of instantiation). This gives better backtraces in diagnostics.
- PointOfInstantiation = Loc;
- }
+ // Implicit instantiation of function templates and member functions of
+ // class templates.
+ if (Func->isImplicitlyInstantiable()) {
+ TemplateSpecializationKind TSK =
+ Func->getTemplateSpecializationKindForInstantiation();
+ SourceLocation PointOfInstantiation = Func->getPointOfInstantiation();
+ bool FirstInstantiation = PointOfInstantiation.isInvalid();
+ if (FirstInstantiation) {
+ PointOfInstantiation = Loc;
+ Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+ } else if (TSK != TSK_ImplicitInstantiation) {
+ // Use the point of use as the point of instantiation, instead of the
+ // point of explicit instantiation (which we track as the actual point
+ // of instantiation). This gives better backtraces in diagnostics.
+ PointOfInstantiation = Loc;
+ }
- if (FirstInstantiation || TSK != TSK_ImplicitInstantiation ||
- Func->isConstexpr()) {
- if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
- cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
- CodeSynthesisContexts.size())
- 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 {
- Func->setInstantiationIsPending(true);
- PendingInstantiations.push_back(
- std::make_pair(Func, PointOfInstantiation));
- // Notify the consumer that a function was implicitly instantiated.
- Consumer.HandleCXXImplicitFunctionInstantiation(Func);
+ if (FirstInstantiation || TSK != TSK_ImplicitInstantiation ||
+ Func->isConstexpr()) {
+ if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
+ cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
+ CodeSynthesisContexts.size())
+ 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 {
+ Func->setInstantiationIsPending(true);
+ 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 (auto i : Func->redecls()) {
+ if (!i->isUsed(false) && i->isImplicitlyInstantiable())
+ MarkFunctionReferenced(Loc, i, MightBeOdrUse);
}
}
- } else {
- // Walk redefinitions, as some of them may be instantiable.
- for (auto i : Func->redecls()) {
- if (!i->isUsed(false) && i->isImplicitlyInstantiable())
- MarkFunctionReferenced(Loc, i, MightBeOdrUse);
- }
- }
+ });
}
// If this is the first "real" use, act on that.
@@ -15207,9 +15603,14 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
CheckCompleteParameterTypesForMangler(*this, Func, Loc);
Func->markUsed(Context);
+ }
- if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)
+ if (LangOpts.OpenMP) {
+ markOpenMPDeclareVariantFuncsReferenced(Loc, Func, MightBeOdrUse);
+ if (LangOpts.OpenMPIsDevice)
checkOpenMPDeviceFunction(Loc, Func);
+ else
+ checkOpenMPHostFunction(Loc, Func);
}
}
@@ -15447,27 +15848,11 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
// Warn about implicitly autoreleasing indirect parameters captured by blocks.
if (const auto *PT = CaptureType->getAs<PointerType>()) {
- // This function finds out whether there is an AttributedType of kind
- // attr::ObjCOwnership in Ty. The existence of AttributedType of kind
- // attr::ObjCOwnership implies __autoreleasing was explicitly specified
- // rather than being added implicitly by the compiler.
- auto IsObjCOwnershipAttributedType = [](QualType Ty) {
- while (const auto *AttrTy = Ty->getAs<AttributedType>()) {
- if (AttrTy->getAttrKind() == attr::ObjCOwnership)
- return true;
-
- // Peel off AttributedTypes that are not of kind ObjCOwnership.
- Ty = AttrTy->getModifiedType();
- }
-
- return false;
- };
-
QualType PointeeTy = PT->getPointeeType();
if (!Invalid && PointeeTy->getAs<ObjCObjectPointerType>() &&
PointeeTy.getObjCLifetime() == Qualifiers::OCL_Autoreleasing &&
- !IsObjCOwnershipAttributedType(PointeeTy)) {
+ !S.Context.hasDirectOwnershipQualifier(PointeeTy)) {
if (BuildAndDiagnose) {
SourceLocation VarLoc = Var->getLocation();
S.Diag(Loc, diag::warn_block_capture_autoreleasing);
@@ -15517,7 +15902,8 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
if (HasConst)
DeclRefType.addConst();
}
- ByRef = S.isOpenMPCapturedByRef(Var, RSI->OpenMPLevel);
+ ByRef = S.isOpenMPCapturedByRef(Var, RSI->OpenMPLevel,
+ RSI->OpenMPCaptureLevel);
}
if (ByRef)
@@ -15745,7 +16131,25 @@ bool Sema::tryCaptureVariable(
// target region should not be captured outside the scope of the region.
if (RSI->CapRegionKind == CR_OpenMP) {
bool IsOpenMPPrivateDecl = isOpenMPPrivateDecl(Var, RSI->OpenMPLevel);
- auto IsTargetCap = !IsOpenMPPrivateDecl &&
+ // If the variable is private (i.e. not captured) and has variably
+ // modified type, we still need to capture the type for correct
+ // codegen in all regions, associated with the construct. Currently,
+ // it is captured in the innermost captured region only.
+ if (IsOpenMPPrivateDecl && Var->getType()->isVariablyModifiedType()) {
+ QualType QTy = Var->getType();
+ if (ParmVarDecl *PVD = dyn_cast_or_null<ParmVarDecl>(Var))
+ QTy = PVD->getOriginalType();
+ for (int I = 1, E = getNumberOfConstructScopes(RSI->OpenMPLevel);
+ I < E; ++I) {
+ auto *OuterRSI = cast<CapturedRegionScopeInfo>(
+ FunctionScopes[FunctionScopesIndex - I]);
+ assert(RSI->OpenMPLevel == OuterRSI->OpenMPLevel &&
+ "Wrong number of captured regions associated with the "
+ "OpenMP construct.");
+ captureVariablyModifiedType(Context, QTy, OuterRSI);
+ }
+ }
+ bool IsTargetCap = !IsOpenMPPrivateDecl &&
isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel);
// When we detect target captures we are looking from inside the
// target region, therefore we need to propagate the capture from the
@@ -16354,7 +16758,9 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
if (UsableInConstantExpr) {
// Do not defer instantiations of variables that could be used in a
// constant expression.
- SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
+ SemaRef.runWithSufficientStackSpace(PointOfInstantiation, [&] {
+ SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
+ });
} else if (FirstInstantiation ||
isa<VarTemplateSpecializationDecl>(Var)) {
// FIXME: For a specialization of a variable template, we don't
@@ -17546,6 +17952,9 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
case BuiltinType::Id:
#include "clang/Basic/OpenCLExtensionTypes.def"
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
#define BUILTIN_TYPE(Id, SingletonId) case BuiltinType::Id:
#define PLACEHOLDER_TYPE(Id, SingletonId)
#include "clang/AST/BuiltinTypes.def"
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 705e3b9bd7fb..9aae9289b514 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -453,6 +453,9 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
if (T->isVariablyModifiedType())
return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << T);
+ if (CheckQualifiedFunctionForTypeId(T, TypeidLoc))
+ return ExprError();
+
return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), Operand,
SourceRange(TypeidLoc, RParenLoc));
}
@@ -496,6 +499,11 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
}
}
+ ExprResult Result = CheckUnevaluatedOperand(E);
+ if (Result.isInvalid())
+ return ExprError();
+ E = Result.get();
+
// C++ [expr.typeid]p4:
// [...] If the type of the type-id is a reference to a possibly
// cv-qualified type, the result of the typeid expression refers to a
@@ -2108,9 +2116,10 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
QualType InitType;
if (KnownArraySize)
InitType = Context.getConstantArrayType(
- AllocType, llvm::APInt(Context.getTypeSize(Context.getSizeType()),
- *KnownArraySize),
- ArrayType::Normal, 0);
+ AllocType,
+ llvm::APInt(Context.getTypeSize(Context.getSizeType()),
+ *KnownArraySize),
+ *ArraySize, ArrayType::Normal, 0);
else if (ArraySize)
InitType =
Context.getIncompleteArrayType(AllocType, ArrayType::Normal, 0);
@@ -2457,8 +2466,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// deallocation function's name is looked up in the global scope.
LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName);
if (AllocElemType->isRecordType() && DeleteScope != AFS_Global) {
- CXXRecordDecl *RD
- = cast<CXXRecordDecl>(AllocElemType->getAs<RecordType>()->getDecl());
+ auto *RD =
+ cast<CXXRecordDecl>(AllocElemType->castAs<RecordType>()->getDecl());
LookupQualifiedName(FoundDelete, RD);
}
if (FoundDelete.isAmbiguous())
@@ -3293,7 +3302,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// itself in this case.
return ExprError();
- QualType Pointee = Type->getAs<PointerType>()->getPointeeType();
+ QualType Pointee = Type->castAs<PointerType>()->getPointeeType();
QualType PointeeElem = Context.getBaseElementType(Pointee);
if (Pointee.getAddressSpace() != LangAS::Default &&
@@ -4025,8 +4034,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
case ICK_Complex_Promotion:
case ICK_Complex_Conversion: {
- QualType FromEl = From->getType()->getAs<ComplexType>()->getElementType();
- QualType ToEl = ToType->getAs<ComplexType>()->getElementType();
+ QualType FromEl = From->getType()->castAs<ComplexType>()->getElementType();
+ QualType ToEl = ToType->castAs<ComplexType>()->getElementType();
CastKind CK;
if (FromEl->isRealFloatingType()) {
if (ToEl->isRealFloatingType())
@@ -4605,7 +4614,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return RD->hasAttr<FinalAttr>();
return false;
case UTT_IsSigned:
- return T->isSignedIntegerType();
+ // Enum types should always return false.
+ // Floating points should always return true.
+ return !T->isEnumeralType() && (T->isFloatingType() || T->isSignedIntegerType());
case UTT_IsUnsigned:
return T->isUnsignedIntegerType();
@@ -5232,7 +5243,13 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl());
ExprResult Result = Self.BuildBinOp(/*S=*/nullptr, KeyLoc, BO_Assign, &Lhs,
&Rhs);
- if (Result.isInvalid() || SFINAE.hasErrorOccurred())
+ if (Result.isInvalid())
+ return false;
+
+ // Treat the assignment as unused for the purpose of -Wdeprecated-volatile.
+ Self.CheckUnusedVolatileAssignment(Result.get());
+
+ if (SFINAE.hasErrorOccurred())
return false;
if (BTT == BTT_IsAssignable)
@@ -5835,20 +5852,21 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
LVK == RVK && LVK != VK_RValue) {
// DerivedToBase was already handled by the class-specific case above.
// FIXME: Should we allow ObjC conversions here?
- bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion;
- if (CompareReferenceRelationship(
- QuestionLoc, LTy, RTy, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible &&
+ bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
+ FunctionConversion;
+ if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, DerivedToBase,
+ ObjCConversion, ObjCLifetimeConversion,
+ FunctionConversion) == Ref_Compatible &&
!DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
// [...] subject to the constraint that the reference must bind
// directly [...]
- !RHS.get()->refersToBitField() &&
- !RHS.get()->refersToVectorElement()) {
+ !RHS.get()->refersToBitField() && !RHS.get()->refersToVectorElement()) {
RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK);
RTy = RHS.get()->getType();
} else if (CompareReferenceRelationship(
- QuestionLoc, RTy, LTy, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible &&
+ QuestionLoc, RTy, LTy, DerivedToBase, ObjCConversion,
+ ObjCLifetimeConversion,
+ FunctionConversion) == Ref_Compatible &&
!DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
!LHS.get()->refersToBitField() &&
!LHS.get()->refersToVectorElement()) {
@@ -6603,6 +6621,11 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
ExprEvalContexts.back().ExprContext =
ExpressionEvaluationContextRecord::EK_Other;
+ Result = CheckUnevaluatedOperand(E);
+ if (Result.isInvalid())
+ return ExprError();
+ E = Result.get();
+
// In MS mode, don't perform any extra checking of call return types within a
// decltype expression.
if (getLangOpts().MSVCCompat)
@@ -6794,14 +6817,10 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
// it's legal for the type to be incomplete if this is a pseudo-destructor
// call. We'll do more incomplete-type checks later in the lookup process,
// so just skip this check for ObjC types.
- if (BaseType->isObjCObjectOrInterfaceType()) {
+ if (!BaseType->isRecordType()) {
ObjectType = ParsedType::make(BaseType);
MayBePseudoDestructor = true;
return Base;
- } else if (!BaseType->isRecordType()) {
- ObjectType = nullptr;
- MayBePseudoDestructor = true;
- return Base;
}
// The object type must be complete (or dependent), or
@@ -7173,7 +7192,7 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
if (Method->getParent()->isLambda() &&
Method->getConversionType()->isBlockPointerType()) {
- // This is a lambda coversion to block pointer; check if the argument
+ // This is a lambda conversion to block pointer; check if the argument
// was a LambdaExpr.
Expr *SubE = E;
CastExpr *CE = dyn_cast<CastExpr>(SubE);
@@ -7231,7 +7250,10 @@ ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand,
if (R.isInvalid())
return R;
- // The operand may have been modified when checking the placeholder type.
+ R = CheckUnevaluatedOperand(R.get());
+ if (R.isInvalid())
+ return ExprError();
+
Operand = R.get();
if (!inTemplateInstantiation() && Operand->HasSideEffects(Context, false)) {
@@ -7335,12 +7357,17 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
// volatile lvalue with a special form, we perform an lvalue-to-rvalue
// conversion.
if (getLangOpts().CPlusPlus11 && E->isGLValue() &&
- E->getType().isVolatileQualified() &&
- IsSpecialDiscardedValue(E)) {
- ExprResult Res = DefaultLvalueConversion(E);
- if (Res.isInvalid())
- return E;
- E = Res.get();
+ E->getType().isVolatileQualified()) {
+ if (IsSpecialDiscardedValue(E)) {
+ ExprResult Res = DefaultLvalueConversion(E);
+ if (Res.isInvalid())
+ return E;
+ E = Res.get();
+ } else {
+ // Per C++2a [expr.ass]p5, a volatile assignment is not deprecated if
+ // it occurs as a discarded-value expression.
+ CheckUnusedVolatileAssignment(E);
+ }
}
// C++1z:
@@ -7375,6 +7402,14 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
return E;
}
+ExprResult Sema::CheckUnevaluatedOperand(Expr *E) {
+ // Per C++2a [expr.ass]p5, a volatile assignment is not deprecated if
+ // it occurs as an unevaluated operand.
+ CheckUnusedVolatileAssignment(E);
+
+ return E;
+}
+
// If we can unambiguously determine whether Var can never be used
// in a constant expression, return true.
// - if the variable and its initializer are non-dependent, then
@@ -7584,15 +7619,22 @@ class TransformTypos : public TreeTransform<TransformTypos> {
llvm::SmallDenseMap<OverloadExpr *, Expr *, 4> OverloadResolution;
/// Emit diagnostics for all of the TypoExprs encountered.
+ ///
/// If the TypoExprs were successfully corrected, then the diagnostics should
/// suggest the corrections. Otherwise the diagnostics will not suggest
/// anything (having been passed an empty TypoCorrection).
- void EmitAllDiagnostics() {
+ ///
+ /// If we've failed to correct due to ambiguous corrections, we need to
+ /// be sure to pass empty corrections and replacements. Otherwise it's
+ /// possible that the Consumer has a TypoCorrection that failed to ambiguity
+ /// and we don't want to report those diagnostics.
+ void EmitAllDiagnostics(bool IsAmbiguous) {
for (TypoExpr *TE : TypoExprs) {
auto &State = SemaRef.getTypoExprState(TE);
if (State.DiagHandler) {
- TypoCorrection TC = State.Consumer->getCurrentCorrection();
- ExprResult Replacement = TransformCache[TE];
+ TypoCorrection TC = IsAmbiguous
+ ? TypoCorrection() : State.Consumer->getCurrentCorrection();
+ ExprResult Replacement = IsAmbiguous ? ExprError() : TransformCache[TE];
// Extract the NamedDecl from the transformed TypoExpr and add it to the
// TypoCorrection, replacing the existing decls. This ensures the right
@@ -7654,6 +7696,149 @@ class TransformTypos : public TreeTransform<TransformTypos> {
return ExprFilter(Res.get());
}
+ // Since correcting typos may intoduce new TypoExprs, this function
+ // checks for new TypoExprs and recurses if it finds any. Note that it will
+ // only succeed if it is able to correct all typos in the given expression.
+ ExprResult CheckForRecursiveTypos(ExprResult Res, bool &IsAmbiguous) {
+ if (Res.isInvalid()) {
+ return Res;
+ }
+ // Check to see if any new TypoExprs were created. If so, we need to recurse
+ // to check their validity.
+ Expr *FixedExpr = Res.get();
+
+ auto SavedTypoExprs = std::move(TypoExprs);
+ auto SavedAmbiguousTypoExprs = std::move(AmbiguousTypoExprs);
+ TypoExprs.clear();
+ AmbiguousTypoExprs.clear();
+
+ FindTypoExprs(TypoExprs).TraverseStmt(FixedExpr);
+ if (!TypoExprs.empty()) {
+ // Recurse to handle newly created TypoExprs. If we're not able to
+ // handle them, discard these TypoExprs.
+ ExprResult RecurResult =
+ RecursiveTransformLoop(FixedExpr, IsAmbiguous);
+ if (RecurResult.isInvalid()) {
+ Res = ExprError();
+ // Recursive corrections didn't work, wipe them away and don't add
+ // them to the TypoExprs set. Remove them from Sema's TypoExpr list
+ // since we don't want to clear them twice. Note: it's possible the
+ // TypoExprs were created recursively and thus won't be in our
+ // Sema's TypoExprs - they were created in our `RecursiveTransformLoop`.
+ auto &SemaTypoExprs = SemaRef.TypoExprs;
+ for (auto TE : TypoExprs) {
+ TransformCache.erase(TE);
+ SemaRef.clearDelayedTypo(TE);
+
+ auto SI = find(SemaTypoExprs, TE);
+ if (SI != SemaTypoExprs.end()) {
+ SemaTypoExprs.erase(SI);
+ }
+ }
+ } else {
+ // TypoExpr is valid: add newly created TypoExprs since we were
+ // able to correct them.
+ Res = RecurResult;
+ SavedTypoExprs.set_union(TypoExprs);
+ }
+ }
+
+ TypoExprs = std::move(SavedTypoExprs);
+ AmbiguousTypoExprs = std::move(SavedAmbiguousTypoExprs);
+
+ return Res;
+ }
+
+ // Try to transform the given expression, looping through the correction
+ // candidates with `CheckAndAdvanceTypoExprCorrectionStreams`.
+ //
+ // If valid ambiguous typo corrections are seen, `IsAmbiguous` is set to
+ // true and this method immediately will return an `ExprError`.
+ ExprResult RecursiveTransformLoop(Expr *E, bool &IsAmbiguous) {
+ ExprResult Res;
+ auto SavedTypoExprs = std::move(SemaRef.TypoExprs);
+ SemaRef.TypoExprs.clear();
+
+ while (true) {
+ Res = CheckForRecursiveTypos(TryTransform(E), IsAmbiguous);
+
+ // Recursion encountered an ambiguous correction. This means that our
+ // correction itself is ambiguous, so stop now.
+ if (IsAmbiguous)
+ break;
+
+ // If the transform is still valid after checking for any new typos,
+ // it's good to go.
+ if (!Res.isInvalid())
+ break;
+
+ // The transform was invalid, see if we have any TypoExprs with untried
+ // correction candidates.
+ if (!CheckAndAdvanceTypoExprCorrectionStreams())
+ break;
+ }
+
+ // If we found a valid result, double check to make sure it's not ambiguous.
+ if (!IsAmbiguous && !Res.isInvalid() && !AmbiguousTypoExprs.empty()) {
+ auto SavedTransformCache = std::move(TransformCache);
+ TransformCache.clear();
+ // Ensure none of the TypoExprs have multiple typo correction candidates
+ // with the same edit length that pass all the checks and filters.
+ while (!AmbiguousTypoExprs.empty()) {
+ auto TE = AmbiguousTypoExprs.back();
+
+ // TryTransform itself can create new Typos, adding them to the TypoExpr map
+ // and invalidating our TypoExprState, so always fetch it instead of storing.
+ SemaRef.getTypoExprState(TE).Consumer->saveCurrentPosition();
+
+ TypoCorrection TC = SemaRef.getTypoExprState(TE).Consumer->peekNextCorrection();
+ TypoCorrection Next;
+ do {
+ // Fetch the next correction by erasing the typo from the cache and calling
+ // `TryTransform` which will iterate through corrections in
+ // `TransformTypoExpr`.
+ TransformCache.erase(TE);
+ ExprResult AmbigRes = CheckForRecursiveTypos(TryTransform(E), IsAmbiguous);
+
+ if (!AmbigRes.isInvalid() || IsAmbiguous) {
+ SemaRef.getTypoExprState(TE).Consumer->resetCorrectionStream();
+ SavedTransformCache.erase(TE);
+ Res = ExprError();
+ IsAmbiguous = true;
+ break;
+ }
+ } while ((Next = SemaRef.getTypoExprState(TE).Consumer->peekNextCorrection()) &&
+ Next.getEditDistance(false) == TC.getEditDistance(false));
+
+ if (IsAmbiguous)
+ break;
+
+ AmbiguousTypoExprs.remove(TE);
+ SemaRef.getTypoExprState(TE).Consumer->restoreSavedPosition();
+ }
+ TransformCache = std::move(SavedTransformCache);
+ }
+
+ // Wipe away any newly created TypoExprs that we don't know about. Since we
+ // clear any invalid TypoExprs in `CheckForRecursiveTypos`, this is only
+ // possible if a `TypoExpr` is created during a transformation but then
+ // fails before we can discover it.
+ auto &SemaTypoExprs = SemaRef.TypoExprs;
+ for (auto Iterator = SemaTypoExprs.begin(); Iterator != SemaTypoExprs.end();) {
+ auto TE = *Iterator;
+ auto FI = find(TypoExprs, TE);
+ if (FI != TypoExprs.end()) {
+ Iterator++;
+ continue;
+ }
+ SemaRef.clearDelayedTypo(TE);
+ Iterator = SemaTypoExprs.erase(Iterator);
+ }
+ SemaRef.TypoExprs = std::move(SavedTypoExprs);
+
+ return Res;
+ }
+
public:
TransformTypos(Sema &SemaRef, VarDecl *InitDecl, llvm::function_ref<ExprResult(Expr *)> Filter)
: BaseTransform(SemaRef), InitDecl(InitDecl), ExprFilter(Filter) {}
@@ -7681,49 +7866,13 @@ public:
ExprResult TransformBlockExpr(BlockExpr *E) { return Owned(E); }
ExprResult Transform(Expr *E) {
- ExprResult Res;
- while (true) {
- Res = TryTransform(E);
-
- // Exit if either the transform was valid or if there were no TypoExprs
- // to transform that still have any untried correction candidates..
- if (!Res.isInvalid() ||
- !CheckAndAdvanceTypoExprCorrectionStreams())
- break;
- }
-
- // Ensure none of the TypoExprs have multiple typo correction candidates
- // with the same edit length that pass all the checks and filters.
- // TODO: Properly handle various permutations of possible corrections when
- // there is more than one potentially ambiguous typo correction.
- // Also, disable typo correction while attempting the transform when
- // handling potentially ambiguous typo corrections as any new TypoExprs will
- // have been introduced by the application of one of the correction
- // candidates and add little to no value if corrected.
- SemaRef.DisableTypoCorrection = true;
- while (!AmbiguousTypoExprs.empty()) {
- auto TE = AmbiguousTypoExprs.back();
- auto Cached = TransformCache[TE];
- auto &State = SemaRef.getTypoExprState(TE);
- State.Consumer->saveCurrentPosition();
- TransformCache.erase(TE);
- if (!TryTransform(E).isInvalid()) {
- State.Consumer->resetCorrectionStream();
- TransformCache.erase(TE);
- Res = ExprError();
- break;
- }
- AmbiguousTypoExprs.remove(TE);
- State.Consumer->restoreSavedPosition();
- TransformCache[TE] = Cached;
- }
- SemaRef.DisableTypoCorrection = false;
+ bool IsAmbiguous = false;
+ ExprResult Res = RecursiveTransformLoop(E, IsAmbiguous);
- // Ensure that all of the TypoExprs within the current Expr have been found.
if (!Res.isUsable())
FindTypoExprs(TypoExprs).TraverseStmt(E);
- EmitAllDiagnostics();
+ EmitAllDiagnostics(IsAmbiguous);
return Res;
}
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index c856e37e99e7..87114a0fac63 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -629,7 +629,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<RecordMemberExprValidatorCCC>(*this);
+ return std::make_unique<RecordMemberExprValidatorCCC>(*this);
}
private:
@@ -934,19 +934,19 @@ static bool IsInFnTryBlockHandler(const Scope *S) {
return false;
}
-static VarDecl *
-getVarTemplateSpecialization(Sema &S, VarTemplateDecl *VarTempl,
+VarDecl *
+Sema::getVarTemplateSpecialization(VarTemplateDecl *VarTempl,
const TemplateArgumentListInfo *TemplateArgs,
const DeclarationNameInfo &MemberNameInfo,
SourceLocation TemplateKWLoc) {
if (!TemplateArgs) {
- S.diagnoseMissingTemplateArguments(TemplateName(VarTempl),
- MemberNameInfo.getBeginLoc());
+ diagnoseMissingTemplateArguments(TemplateName(VarTempl),
+ MemberNameInfo.getBeginLoc());
return nullptr;
}
- DeclResult VDecl = S.CheckVarTemplateId(
- VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(), *TemplateArgs);
+ DeclResult VDecl = CheckVarTemplateId(VarTempl, TemplateKWLoc,
+ MemberNameInfo.getLoc(), *TemplateArgs);
if (VDecl.isInvalid())
return nullptr;
VarDecl *Var = cast<VarDecl>(VDecl.get());
@@ -1006,7 +1006,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
// Rederive where we looked up.
DeclContext *DC = (SS.isSet()
? computeDeclContext(SS, false)
- : BaseType->getAs<RecordType>()->getDecl());
+ : BaseType->castAs<RecordType>()->getDecl());
if (ExtraArgs) {
ExprResult RetryExpr;
@@ -1095,7 +1095,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
"How did we get template arguments here sans a variable template");
if (isa<VarTemplateDecl>(MemberDecl)) {
MemberDecl = getVarTemplateSpecialization(
- *this, cast<VarTemplateDecl>(MemberDecl), TemplateArgs,
+ cast<VarTemplateDecl>(MemberDecl), TemplateArgs,
R.getLookupNameInfo(), TemplateKWLoc);
if (!MemberDecl)
return ExprError();
@@ -1160,7 +1160,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
}
if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) {
if (VarDecl *Var = getVarTemplateSpecialization(
- *this, VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc))
+ VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc))
return BuildMemberExpr(
BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, FoundDecl,
/*HadMultipleCandidates=*/false, MemberNameInfo,
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 040cfdd30c7a..e18621e42a6b 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -67,7 +67,7 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
const ConstantArrayType *CAT = Context.getAsConstantArrayType(S->getType());
assert(CAT && "String literal not of constant array type!");
QualType StrTy = Context.getConstantArrayType(
- CAT->getElementType(), llvm::APInt(32, StrBuf.size() + 1),
+ CAT->getElementType(), llvm::APInt(32, StrBuf.size() + 1), nullptr,
CAT->getSizeModifier(), CAT->getIndexTypeCVRQualifiers());
S = StringLiteral::Create(Context, StrBuf, StringLiteral::Ascii,
/*Pascal=*/false, StrTy, &StrLocs[0],
@@ -2115,7 +2115,7 @@ class ObjCInterfaceOrSuperCCC final : public CorrectionCandidateCallback {
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<ObjCInterfaceOrSuperCCC>(*this);
+ return std::make_unique<ObjCInterfaceOrSuperCCC>(*this);
}
};
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index bc1069609336..10cb7acad567 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Designator.h"
#include "clang/Sema/Initialization.h"
@@ -197,7 +198,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
llvm::APInt ConstVal(32, StrLength);
// Return a new array type (C99 6.7.8p22).
DeclT = S.Context.getConstantArrayType(IAT->getElementType(),
- ConstVal,
+ ConstVal, nullptr,
ArrayType::Normal, 0);
updateStringLiteralType(Str, DeclT);
return;
@@ -271,13 +272,24 @@ namespace {
/// point. CheckDesignatedInitializer() recursively steps into the
/// designated subobject and manages backing out the recursion to
/// initialize the subobjects after the one designated.
+///
+/// If an initializer list contains any designators, we build a placeholder
+/// structured list even in 'verify only' mode, so that we can track which
+/// elements need 'empty' initializtion.
class InitListChecker {
Sema &SemaRef;
- bool hadError;
- bool VerifyOnly; // no diagnostics, no structure building
+ bool hadError = false;
+ bool VerifyOnly; // No diagnostics.
bool TreatUnavailableAsInvalid; // Used only in VerifyOnly mode.
- llvm::DenseMap<InitListExpr *, InitListExpr *> SyntacticToSemantic;
- InitListExpr *FullyStructuredList;
+ bool InOverloadResolution;
+ InitListExpr *FullyStructuredList = nullptr;
+ NoInitExpr *DummyExpr = nullptr;
+
+ NoInitExpr *getDummyInit() {
+ if (!DummyExpr)
+ DummyExpr = new (SemaRef.Context) NoInitExpr(SemaRef.Context.VoidTy);
+ return DummyExpr;
+ }
void CheckImplicitInitList(const InitializedEntity &Entity,
InitListExpr *ParentIList, QualType T,
@@ -352,14 +364,71 @@ class InitListChecker {
void UpdateStructuredListElement(InitListExpr *StructuredList,
unsigned &StructuredIndex,
Expr *expr);
+ InitListExpr *createInitListExpr(QualType CurrentObjectType,
+ SourceRange InitRange,
+ unsigned ExpectedNumInits);
int numArrayElements(QualType DeclType);
int numStructUnionElements(QualType DeclType);
- static ExprResult PerformEmptyInit(Sema &SemaRef,
- SourceLocation Loc,
- const InitializedEntity &Entity,
- bool VerifyOnly,
- bool TreatUnavailableAsInvalid);
+ ExprResult PerformEmptyInit(SourceLocation Loc,
+ const InitializedEntity &Entity);
+
+ /// Diagnose that OldInit (or part thereof) has been overridden by NewInit.
+ void diagnoseInitOverride(Expr *OldInit, SourceRange NewInitRange,
+ bool FullyOverwritten = true) {
+ // Overriding an initializer via a designator is valid with C99 designated
+ // initializers, but ill-formed with C++20 designated initializers.
+ unsigned DiagID = SemaRef.getLangOpts().CPlusPlus
+ ? diag::ext_initializer_overrides
+ : diag::warn_initializer_overrides;
+
+ if (InOverloadResolution && SemaRef.getLangOpts().CPlusPlus) {
+ // In overload resolution, we have to strictly enforce the rules, and so
+ // don't allow any overriding of prior initializers. This matters for a
+ // case such as:
+ //
+ // union U { int a, b; };
+ // struct S { int a, b; };
+ // void f(U), f(S);
+ //
+ // Here, f({.a = 1, .b = 2}) is required to call the struct overload. For
+ // consistency, we disallow all overriding of prior initializers in
+ // overload resolution, not only overriding of union members.
+ hadError = true;
+ } else if (OldInit->getType().isDestructedType() && !FullyOverwritten) {
+ // If we'll be keeping around the old initializer but overwriting part of
+ // the object it initialized, and that object is not trivially
+ // destructible, this can leak. Don't allow that, not even as an
+ // extension.
+ //
+ // FIXME: It might be reasonable to allow this in cases where the part of
+ // the initializer that we're overriding has trivial destruction.
+ DiagID = diag::err_initializer_overrides_destructed;
+ } else if (!OldInit->getSourceRange().isValid()) {
+ // We need to check on source range validity because the previous
+ // initializer does not have to be an explicit initializer. e.g.,
+ //
+ // struct P { int a, b; };
+ // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 };
+ //
+ // There is an overwrite taking place because the first braced initializer
+ // list "{ .a = 2 }" already provides value for .p.b (which is zero).
+ //
+ // Such overwrites are harmless, so we don't diagnose them. (Note that in
+ // C++, this cannot be reached unless we've already seen and diagnosed a
+ // different conformance issue, such as a mixture of designated and
+ // non-designated initializers or a multi-level designator.)
+ return;
+ }
+
+ if (!VerifyOnly) {
+ SemaRef.Diag(NewInitRange.getBegin(), DiagID)
+ << NewInitRange << FullyOverwritten << OldInit->getType();
+ SemaRef.Diag(OldInit->getBeginLoc(), diag::note_previous_initializer)
+ << (OldInit->HasSideEffects(SemaRef.Context) && FullyOverwritten)
+ << OldInit->getSourceRange();
+ }
+ }
// Explanation on the "FillWithNoInit" mode:
//
@@ -399,9 +468,9 @@ class InitListChecker {
SourceLocation Loc);
public:
- InitListChecker(Sema &S, const InitializedEntity &Entity,
- InitListExpr *IL, QualType &T, bool VerifyOnly,
- bool TreatUnavailableAsInvalid);
+ InitListChecker(Sema &S, const InitializedEntity &Entity, InitListExpr *IL,
+ QualType &T, bool VerifyOnly, bool TreatUnavailableAsInvalid,
+ bool InOverloadResolution = false);
bool HadError() { return hadError; }
// Retrieves the fully-structured initializer list used for
@@ -411,11 +480,8 @@ public:
} // end anonymous namespace
-ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef,
- SourceLocation Loc,
- const InitializedEntity &Entity,
- bool VerifyOnly,
- bool TreatUnavailableAsInvalid) {
+ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc,
+ const InitializedEntity &Entity) {
InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
true);
MultiExprArg SubInit;
@@ -517,43 +583,44 @@ ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef,
<< Entity.getElementIndex();
}
}
+ hadError = true;
return ExprError();
}
- return VerifyOnly ? ExprResult(static_cast<Expr *>(nullptr))
+ return VerifyOnly ? ExprResult()
: InitSeq.Perform(SemaRef, Entity, Kind, SubInit);
}
void InitListChecker::CheckEmptyInitializable(const InitializedEntity &Entity,
SourceLocation Loc) {
- assert(VerifyOnly &&
- "CheckEmptyInitializable is only inteded for verification mode.");
- if (PerformEmptyInit(SemaRef, Loc, Entity, /*VerifyOnly*/true,
- TreatUnavailableAsInvalid).isInvalid())
- hadError = true;
+ // If we're building a fully-structured list, we'll check this at the end
+ // once we know which elements are actually initialized. Otherwise, we know
+ // that there are no designators so we can just check now.
+ if (FullyStructuredList)
+ return;
+ PerformEmptyInit(Loc, Entity);
}
void InitListChecker::FillInEmptyInitForBase(
unsigned Init, const CXXBaseSpecifier &Base,
const InitializedEntity &ParentEntity, InitListExpr *ILE,
bool &RequiresSecondPass, bool FillWithNoInit) {
- assert(Init < ILE->getNumInits() && "should have been expanded");
-
InitializedEntity BaseEntity = InitializedEntity::InitializeBase(
SemaRef.Context, &Base, false, &ParentEntity);
- if (!ILE->getInit(Init)) {
- ExprResult BaseInit =
- FillWithNoInit
- ? new (SemaRef.Context) NoInitExpr(Base.getType())
- : PerformEmptyInit(SemaRef, ILE->getEndLoc(), BaseEntity,
- /*VerifyOnly*/ false, TreatUnavailableAsInvalid);
+ if (Init >= ILE->getNumInits() || !ILE->getInit(Init)) {
+ ExprResult BaseInit = FillWithNoInit
+ ? new (SemaRef.Context) NoInitExpr(Base.getType())
+ : PerformEmptyInit(ILE->getEndLoc(), BaseEntity);
if (BaseInit.isInvalid()) {
hadError = true;
return;
}
- ILE->setInit(Init, BaseInit.getAs<Expr>());
+ if (!VerifyOnly) {
+ assert(Init < ILE->getNumInits() && "should have been expanded");
+ ILE->setInit(Init, BaseInit.getAs<Expr>());
+ }
} else if (InitListExpr *InnerILE =
dyn_cast<InitListExpr>(ILE->getInit(Init))) {
FillInEmptyInitializations(BaseEntity, InnerILE, RequiresSecondPass,
@@ -576,12 +643,14 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
InitializedEntity MemberEntity
= InitializedEntity::InitializeMember(Field, &ParentEntity);
- if (const RecordType *RType = ILE->getType()->getAs<RecordType>())
- if (!RType->getDecl()->isUnion())
- assert(Init < NumInits && "This ILE should have been expanded");
-
if (Init >= NumInits || !ILE->getInit(Init)) {
+ if (const RecordType *RType = ILE->getType()->getAs<RecordType>())
+ if (!RType->getDecl()->isUnion())
+ assert((Init < NumInits || VerifyOnly) &&
+ "This ILE should have been expanded");
+
if (FillWithNoInit) {
+ assert(!VerifyOnly && "should not fill with no-init in verify-only mode");
Expr *Filler = new (SemaRef.Context) NoInitExpr(Field->getType());
if (Init < NumInits)
ILE->setInit(Init, Filler);
@@ -594,6 +663,9 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
// members in the aggregate, then each member not explicitly initialized
// shall be initialized from its brace-or-equal-initializer [...]
if (Field->hasInClassInitializer()) {
+ if (VerifyOnly)
+ return;
+
ExprResult DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field);
if (DIE.isInvalid()) {
hadError = true;
@@ -610,28 +682,28 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
}
if (Field->getType()->isReferenceType()) {
- // C++ [dcl.init.aggr]p9:
- // If an incomplete or empty initializer-list leaves a
- // member of reference type uninitialized, the program is
- // ill-formed.
- SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized)
- << Field->getType()
- << ILE->getSyntacticForm()->getSourceRange();
- SemaRef.Diag(Field->getLocation(),
- diag::note_uninit_reference_member);
+ if (!VerifyOnly) {
+ // C++ [dcl.init.aggr]p9:
+ // If an incomplete or empty initializer-list leaves a
+ // member of reference type uninitialized, the program is
+ // ill-formed.
+ SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized)
+ << Field->getType()
+ << ILE->getSyntacticForm()->getSourceRange();
+ SemaRef.Diag(Field->getLocation(),
+ diag::note_uninit_reference_member);
+ }
hadError = true;
return;
}
- ExprResult MemberInit = PerformEmptyInit(SemaRef, Loc, MemberEntity,
- /*VerifyOnly*/false,
- TreatUnavailableAsInvalid);
+ ExprResult MemberInit = PerformEmptyInit(Loc, MemberEntity);
if (MemberInit.isInvalid()) {
hadError = true;
return;
}
- if (hadError) {
+ if (hadError || VerifyOnly) {
// Do nothing
} else if (Init < NumInits) {
ILE->setInit(Init, MemberInit.getAs<Expr>());
@@ -644,14 +716,15 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
RequiresSecondPass = true;
}
} else if (InitListExpr *InnerILE
- = dyn_cast<InitListExpr>(ILE->getInit(Init)))
+ = dyn_cast<InitListExpr>(ILE->getInit(Init))) {
FillInEmptyInitializations(MemberEntity, InnerILE,
RequiresSecondPass, ILE, Init, FillWithNoInit);
- else if (DesignatedInitUpdateExpr *InnerDIUE
- = dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init)))
+ } else if (DesignatedInitUpdateExpr *InnerDIUE =
+ dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init))) {
FillInEmptyInitializations(MemberEntity, InnerDIUE->getUpdater(),
RequiresSecondPass, ILE, Init,
/*FillWithNoInit =*/true);
+ }
}
/// Recursively replaces NULL values within the given initializer list
@@ -667,6 +740,11 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
assert((ILE->getType() != SemaRef.Context.VoidTy) &&
"Should not have void type");
+ // We don't need to do any checks when just filling NoInitExprs; that can't
+ // fail.
+ if (FillWithNoInit && VerifyOnly)
+ return;
+
// If this is a nested initializer list, we might have changed its contents
// (and therefore some of its properties, such as instantiation-dependence)
// while filling it in. Inform the outer initializer list so that its state
@@ -709,7 +787,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
unsigned NumElems = numStructUnionElements(ILE->getType());
if (RDecl->hasFlexibleArrayMember())
++NumElems;
- if (ILE->getNumInits() < NumElems)
+ if (!VerifyOnly && ILE->getNumInits() < NumElems)
ILE->resizeInits(SemaRef.Context, NumElems);
unsigned Init = 0;
@@ -771,6 +849,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
} else
ElementType = ILE->getType();
+ bool SkipEmptyInitChecks = false;
for (unsigned Init = 0; Init != NumElements; ++Init) {
if (hadError)
return;
@@ -779,21 +858,25 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
ElementEntity.getKind() == InitializedEntity::EK_VectorElement)
ElementEntity.setElementIndex(Init);
- if (Init >= NumInits && ILE->hasArrayFiller())
+ if (Init >= NumInits && (ILE->hasArrayFiller() || SkipEmptyInitChecks))
return;
Expr *InitExpr = (Init < NumInits ? ILE->getInit(Init) : nullptr);
if (!InitExpr && Init < NumInits && ILE->hasArrayFiller())
ILE->setInit(Init, ILE->getArrayFiller());
else if (!InitExpr && !ILE->hasArrayFiller()) {
+ // In VerifyOnly mode, there's no point performing empty initialization
+ // more than once.
+ if (SkipEmptyInitChecks)
+ continue;
+
Expr *Filler = nullptr;
if (FillWithNoInit)
Filler = new (SemaRef.Context) NoInitExpr(ElementType);
else {
ExprResult ElementInit =
- PerformEmptyInit(SemaRef, ILE->getEndLoc(), ElementEntity,
- /*VerifyOnly*/ false, TreatUnavailableAsInvalid);
+ PerformEmptyInit(ILE->getEndLoc(), ElementEntity);
if (ElementInit.isInvalid()) {
hadError = true;
return;
@@ -804,6 +887,8 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
if (hadError) {
// Do nothing
+ } else if (VerifyOnly) {
+ SkipEmptyInitChecks = true;
} else if (Init < NumInits) {
// For arrays, just set the expression used for value-initialization
// of the "holes" in the array.
@@ -829,34 +914,46 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
}
}
} else if (InitListExpr *InnerILE
- = dyn_cast_or_null<InitListExpr>(InitExpr))
+ = dyn_cast_or_null<InitListExpr>(InitExpr)) {
FillInEmptyInitializations(ElementEntity, InnerILE, RequiresSecondPass,
ILE, Init, FillWithNoInit);
- else if (DesignatedInitUpdateExpr *InnerDIUE
- = dyn_cast_or_null<DesignatedInitUpdateExpr>(InitExpr))
+ } else if (DesignatedInitUpdateExpr *InnerDIUE =
+ dyn_cast_or_null<DesignatedInitUpdateExpr>(InitExpr)) {
FillInEmptyInitializations(ElementEntity, InnerDIUE->getUpdater(),
RequiresSecondPass, ILE, Init,
/*FillWithNoInit =*/true);
+ }
}
}
+static bool hasAnyDesignatedInits(const InitListExpr *IL) {
+ for (const Stmt *Init : *IL)
+ if (Init && isa<DesignatedInitExpr>(Init))
+ return true;
+ return false;
+}
+
InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
- InitListExpr *IL, QualType &T,
- bool VerifyOnly,
- bool TreatUnavailableAsInvalid)
- : SemaRef(S), VerifyOnly(VerifyOnly),
- TreatUnavailableAsInvalid(TreatUnavailableAsInvalid) {
- // FIXME: Check that IL isn't already the semantic form of some other
- // InitListExpr. If it is, we'd create a broken AST.
-
- hadError = false;
-
- FullyStructuredList =
- getStructuredSubobjectInit(IL, 0, T, nullptr, 0, IL->getSourceRange());
+ InitListExpr *IL, QualType &T, bool VerifyOnly,
+ bool TreatUnavailableAsInvalid,
+ bool InOverloadResolution)
+ : SemaRef(S), VerifyOnly(VerifyOnly),
+ TreatUnavailableAsInvalid(TreatUnavailableAsInvalid),
+ InOverloadResolution(InOverloadResolution) {
+ if (!VerifyOnly || hasAnyDesignatedInits(IL)) {
+ FullyStructuredList =
+ createInitListExpr(T, IL->getSourceRange(), IL->getNumInits());
+
+ // FIXME: Check that IL isn't already the semantic form of some other
+ // InitListExpr. If it is, we'd create a broken AST.
+ if (!VerifyOnly)
+ FullyStructuredList->setSyntacticForm(IL);
+ }
+
CheckExplicitInitList(Entity, IL, T, FullyStructuredList,
/*TopLevelObject=*/true);
- if (!hadError && !VerifyOnly) {
+ if (!hadError && FullyStructuredList) {
bool RequiresSecondPass = false;
FillInEmptyInitializations(Entity, FullyStructuredList, RequiresSecondPass,
/*OuterILE=*/nullptr, /*OuterIndex=*/0);
@@ -877,7 +974,7 @@ int InitListChecker::numArrayElements(QualType DeclType) {
}
int InitListChecker::numStructUnionElements(QualType DeclType) {
- RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl();
+ RecordDecl *structDecl = DeclType->castAs<RecordType>()->getDecl();
int InitializableMembers = 0;
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(structDecl))
InitializableMembers += CXXRD->getNumBases();
@@ -936,7 +1033,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
else if (T->isRecordType())
maxElements = numStructUnionElements(T);
else if (T->isVectorType())
- maxElements = T->getAs<VectorType>()->getNumElements();
+ maxElements = T->castAs<VectorType>()->getNumElements();
else
llvm_unreachable("CheckImplicitInitList(): Illegal type");
@@ -963,7 +1060,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
StructuredSubobjectInitList,
StructuredSubobjectInitIndex);
- if (!VerifyOnly) {
+ if (StructuredSubobjectInitList) {
StructuredSubobjectInitList->setType(T);
unsigned EndIndex = (Index == StartIndex? StartIndex : Index - 1);
@@ -977,7 +1074,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
}
// Complain about missing braces.
- if ((T->isArrayType() || T->isRecordType()) &&
+ if (!VerifyOnly && (T->isArrayType() || T->isRecordType()) &&
!ParentIList->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) &&
!isIdiomaticBraceElisionEntity(Entity)) {
SemaRef.Diag(StructuredSubobjectInitList->getBeginLoc(),
@@ -993,7 +1090,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity,
// Warn if this type won't be an aggregate in future versions of C++.
auto *CXXRD = T->getAsCXXRecordDecl();
- if (CXXRD && CXXRD->hasUserDeclaredConstructor()) {
+ if (!VerifyOnly && CXXRD && CXXRD->hasUserDeclaredConstructor()) {
SemaRef.Diag(StructuredSubobjectInitList->getBeginLoc(),
diag::warn_cxx2a_compat_aggregate_init_with_ctors)
<< StructuredSubobjectInitList->getSourceRange() << T;
@@ -1074,67 +1171,46 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
InitListExpr *IList, QualType &T,
InitListExpr *StructuredList,
bool TopLevelObject) {
- if (!VerifyOnly) {
- SyntacticToSemantic[IList] = StructuredList;
- StructuredList->setSyntacticForm(IList);
- }
-
unsigned Index = 0, StructuredIndex = 0;
CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true,
Index, StructuredList, StructuredIndex, TopLevelObject);
- if (!VerifyOnly) {
+ if (StructuredList) {
QualType ExprTy = T;
if (!ExprTy->isArrayType())
ExprTy = ExprTy.getNonLValueExprType(SemaRef.Context);
- IList->setType(ExprTy);
+ if (!VerifyOnly)
+ IList->setType(ExprTy);
StructuredList->setType(ExprTy);
}
if (hadError)
return;
- if (Index < IList->getNumInits()) {
+ // Don't complain for incomplete types, since we'll get an error elsewhere.
+ if (Index < IList->getNumInits() && !T->isIncompleteType()) {
// We have leftover initializers
+ bool ExtraInitsIsError = SemaRef.getLangOpts().CPlusPlus ||
+ (SemaRef.getLangOpts().OpenCL && T->isVectorType());
+ hadError = ExtraInitsIsError;
if (VerifyOnly) {
- if (SemaRef.getLangOpts().CPlusPlus ||
- (SemaRef.getLangOpts().OpenCL &&
- IList->getType()->isVectorType())) {
- hadError = true;
- }
return;
- }
-
- if (StructuredIndex == 1 &&
- IsStringInit(StructuredList->getInit(0), T, SemaRef.Context) ==
- SIF_None) {
- unsigned DK = diag::ext_excess_initializers_in_char_array_initializer;
- if (SemaRef.getLangOpts().CPlusPlus) {
- DK = diag::err_excess_initializers_in_char_array_initializer;
- hadError = true;
- }
- // Special-case
+ } else if (StructuredIndex == 1 &&
+ IsStringInit(StructuredList->getInit(0), T, SemaRef.Context) ==
+ SIF_None) {
+ unsigned DK =
+ ExtraInitsIsError
+ ? diag::err_excess_initializers_in_char_array_initializer
+ : diag::ext_excess_initializers_in_char_array_initializer;
SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK)
<< IList->getInit(Index)->getSourceRange();
- } else if (!T->isIncompleteType()) {
- // Don't complain for incomplete types, since we'll get an error
- // elsewhere
- QualType CurrentObjectType = StructuredList->getType();
- int initKind =
- CurrentObjectType->isArrayType()? 0 :
- CurrentObjectType->isVectorType()? 1 :
- CurrentObjectType->isScalarType()? 2 :
- CurrentObjectType->isUnionType()? 3 :
- 4;
-
- unsigned DK = diag::ext_excess_initializers;
- if (SemaRef.getLangOpts().CPlusPlus) {
- DK = diag::err_excess_initializers;
- hadError = true;
- }
- if (SemaRef.getLangOpts().OpenCL && initKind == 1) {
- DK = diag::err_excess_initializers;
- hadError = true;
- }
-
+ } else {
+ int initKind = T->isArrayType() ? 0 :
+ T->isVectorType() ? 1 :
+ T->isScalarType() ? 2 :
+ T->isUnionType() ? 3 :
+ 4;
+
+ unsigned DK = ExtraInitsIsError ? diag::err_excess_initializers
+ : diag::ext_excess_initializers;
SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK)
<< initKind << IList->getInit(Index)->getSourceRange();
}
@@ -1188,7 +1264,7 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
} else if (DeclType->isRecordType()) {
assert(DeclType->isAggregateType() &&
"non-aggregate records should be handed in CheckSubElementType");
- RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
auto Bases =
CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(),
CXXRecordDecl::base_class_iterator());
@@ -1246,42 +1322,22 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
if (SubInitList->getNumInits() == 1 &&
IsStringInit(SubInitList->getInit(0), ElemType, SemaRef.Context) ==
SIF_None) {
+ // FIXME: It would be more faithful and no less correct to include an
+ // InitListExpr in the semantic form of the initializer list in this case.
expr = SubInitList->getInit(0);
- } else if (!SemaRef.getLangOpts().CPlusPlus) {
- InitListExpr *InnerStructuredList
- = getStructuredSubobjectInit(IList, Index, ElemType,
- StructuredList, StructuredIndex,
- SubInitList->getSourceRange(), true);
- CheckExplicitInitList(Entity, SubInitList, ElemType,
- InnerStructuredList);
-
- if (!hadError && !VerifyOnly) {
- bool RequiresSecondPass = false;
- FillInEmptyInitializations(Entity, InnerStructuredList,
- RequiresSecondPass, StructuredList,
- StructuredIndex);
- if (RequiresSecondPass && !hadError)
- FillInEmptyInitializations(Entity, InnerStructuredList,
- RequiresSecondPass, StructuredList,
- StructuredIndex);
- }
- ++StructuredIndex;
- ++Index;
- return;
}
- // C++ initialization is handled later.
+ // Nested aggregate initialization and C++ initialization are handled later.
} else if (isa<ImplicitValueInitExpr>(expr)) {
// This happens during template instantiation when we see an InitListExpr
// that we've already checked once.
assert(SemaRef.Context.hasSameType(expr->getType(), ElemType) &&
"found implicit initialization for the wrong type");
- if (!VerifyOnly)
- UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
+ UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
++Index;
return;
}
- if (SemaRef.getLangOpts().CPlusPlus) {
+ if (SemaRef.getLangOpts().CPlusPlus || isa<InitListExpr>(expr)) {
// C++ [dcl.init.aggr]p2:
// Each member is copy-initialized from the corresponding
// initializer-clause.
@@ -1289,7 +1345,16 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// FIXME: Better EqualLoc?
InitializationKind Kind =
InitializationKind::CreateCopy(expr->getBeginLoc(), SourceLocation());
- InitializationSequence Seq(SemaRef, Entity, Kind, expr,
+
+ // Vector elements can be initialized from other vectors in which case
+ // we need initialization entity with a type of a vector (and not a vector
+ // element!) initializing multiple vector elements.
+ auto TmpEntity =
+ (ElemType->isExtVectorType() && !Entity.getType()->isExtVectorType())
+ ? InitializedEntity::InitializeTemporary(ElemType)
+ : Entity;
+
+ InitializationSequence Seq(SemaRef, TmpEntity, Kind, expr,
/*TopLevelOfInitList*/ true);
// C++14 [dcl.init.aggr]p13:
@@ -1300,15 +1365,18 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// assignment-expression.
if (Seq || isa<InitListExpr>(expr)) {
if (!VerifyOnly) {
- ExprResult Result =
- Seq.Perform(SemaRef, Entity, Kind, expr);
+ ExprResult Result = Seq.Perform(SemaRef, TmpEntity, Kind, expr);
if (Result.isInvalid())
hadError = true;
UpdateStructuredListElement(StructuredList, StructuredIndex,
Result.getAs<Expr>());
- } else if (!Seq)
+ } else if (!Seq) {
hadError = true;
+ } else if (StructuredList) {
+ UpdateStructuredListElement(StructuredList, StructuredIndex,
+ getDummyInit());
+ }
++Index;
return;
}
@@ -1325,10 +1393,11 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// type here, though.
if (IsStringInit(expr, arrayType, SemaRef.Context) == SIF_None) {
- if (!VerifyOnly) {
+ // FIXME: Should we do this checking in verify-only mode?
+ if (!VerifyOnly)
CheckStringInit(expr, ElemType, arrayType, SemaRef);
+ if (StructuredList)
UpdateStructuredListElement(StructuredList, StructuredIndex, expr);
- }
++Index;
return;
}
@@ -1354,8 +1423,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
hadError = true;
else {
ExprRes = SemaRef.DefaultFunctionArrayLvalueConversion(ExprRes.get());
- if (ExprRes.isInvalid())
- hadError = true;
+ if (ExprRes.isInvalid())
+ hadError = true;
}
UpdateStructuredListElement(StructuredList, StructuredIndex,
ExprRes.getAs<Expr>());
@@ -1380,10 +1449,15 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
++StructuredIndex;
} else {
if (!VerifyOnly) {
- // We cannot initialize this element, so let
- // PerformCopyInitialization produce the appropriate diagnostic.
- SemaRef.PerformCopyInitialization(Entity, SourceLocation(), expr,
- /*TopLevelOfInitList=*/true);
+ // We cannot initialize this element, so let PerformCopyInitialization
+ // produce the appropriate diagnostic. We already checked that this
+ // initialization will fail.
+ ExprResult Copy =
+ SemaRef.PerformCopyInitialization(Entity, SourceLocation(), expr,
+ /*TopLevelOfInitList=*/true);
+ (void)Copy;
+ assert(Copy.isInvalid() &&
+ "expected non-aggregate initialization to fail");
}
hadError = true;
++Index;
@@ -1416,7 +1490,7 @@ void InitListChecker::CheckComplexType(const InitializedEntity &Entity,
<< IList->getSourceRange();
// Initialize the complex number.
- QualType elementType = DeclType->getAs<ComplexType>()->getElementType();
+ QualType elementType = DeclType->castAs<ComplexType>()->getElementType();
InitializedEntity ElementEntity =
InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);
@@ -1467,17 +1541,18 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
return;
}
+ ExprResult Result;
if (VerifyOnly) {
- if (!SemaRef.CanPerformCopyInitialization(Entity,expr))
- hadError = true;
- ++Index;
- return;
+ if (SemaRef.CanPerformCopyInitialization(Entity, expr))
+ Result = getDummyInit();
+ else
+ Result = ExprError();
+ } else {
+ Result =
+ SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr,
+ /*TopLevelOfInitList=*/true);
}
- ExprResult Result =
- SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr,
- /*TopLevelOfInitList=*/true);
-
Expr *ResultExpr = nullptr;
if (Result.isInvalid())
@@ -1485,8 +1560,9 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
else {
ResultExpr = Result.getAs<Expr>();
- if (ResultExpr != expr) {
+ if (ResultExpr != expr && !VerifyOnly) {
// The type was promoted, update initializer list.
+ // FIXME: Why are we updating the syntactic init list?
IList->setInit(Index, ResultExpr);
}
}
@@ -1528,22 +1604,25 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity,
return;
}
+ ExprResult Result;
if (VerifyOnly) {
- if (!SemaRef.CanPerformCopyInitialization(Entity,expr))
- hadError = true;
- ++Index;
- return;
+ if (SemaRef.CanPerformCopyInitialization(Entity,expr))
+ Result = getDummyInit();
+ else
+ Result = ExprError();
+ } else {
+ Result =
+ SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr,
+ /*TopLevelOfInitList=*/true);
}
- ExprResult Result =
- SemaRef.PerformCopyInitialization(Entity, expr->getBeginLoc(), expr,
- /*TopLevelOfInitList=*/true);
-
if (Result.isInvalid())
hadError = true;
expr = Result.getAs<Expr>();
- IList->setInit(Index, expr);
+ // FIXME: Why are we updating the syntactic init list?
+ if (!VerifyOnly)
+ IList->setInit(Index, expr);
if (hadError)
++StructuredIndex;
@@ -1557,17 +1636,16 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
- const VectorType *VT = DeclType->getAs<VectorType>();
+ const VectorType *VT = DeclType->castAs<VectorType>();
unsigned maxElements = VT->getNumElements();
unsigned numEltsInit = 0;
QualType elementType = VT->getElementType();
if (Index >= IList->getNumInits()) {
// Make sure the element type can be value-initialized.
- if (VerifyOnly)
- CheckEmptyInitializable(
- InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity),
- IList->getEndLoc());
+ CheckEmptyInitializable(
+ InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity),
+ IList->getEndLoc());
return;
}
@@ -1576,25 +1654,27 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
// instead of breaking it apart (which is doomed to failure anyway).
Expr *Init = IList->getInit(Index);
if (!isa<InitListExpr>(Init) && Init->getType()->isVectorType()) {
+ ExprResult Result;
if (VerifyOnly) {
- if (!SemaRef.CanPerformCopyInitialization(Entity, Init))
- hadError = true;
- ++Index;
- return;
+ if (SemaRef.CanPerformCopyInitialization(Entity, Init))
+ Result = getDummyInit();
+ else
+ Result = ExprError();
+ } else {
+ Result =
+ SemaRef.PerformCopyInitialization(Entity, Init->getBeginLoc(), Init,
+ /*TopLevelOfInitList=*/true);
}
- ExprResult Result =
- SemaRef.PerformCopyInitialization(Entity, Init->getBeginLoc(), Init,
- /*TopLevelOfInitList=*/true);
-
Expr *ResultExpr = nullptr;
if (Result.isInvalid())
hadError = true; // types weren't compatible.
else {
ResultExpr = Result.getAs<Expr>();
- if (ResultExpr != Init) {
+ if (ResultExpr != Init && !VerifyOnly) {
// The type was promoted, update initializer list.
+ // FIXME: Why are we updating the syntactic init list?
IList->setInit(Index, ResultExpr);
}
}
@@ -1613,8 +1693,7 @@ 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 (VerifyOnly)
- CheckEmptyInitializable(ElementEntity, IList->getEndLoc());
+ CheckEmptyInitializable(ElementEntity, IList->getEndLoc());
break;
}
@@ -1627,7 +1706,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
return;
bool isBigEndian = SemaRef.Context.getTargetInfo().isBigEndian();
- const VectorType *T = Entity.getType()->getAs<VectorType>();
+ const VectorType *T = Entity.getType()->castAs<VectorType>();
if (isBigEndian && (T->getVectorKind() == VectorType::NeonVector ||
T->getVectorKind() == VectorType::NeonPolyVector)) {
// The ability to use vector initializer lists is a GNU vector extension
@@ -1683,7 +1762,7 @@ void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
++numEltsInit;
} else {
QualType VecType;
- const VectorType *IVT = IType->getAs<VectorType>();
+ const VectorType *IVT = IType->castAs<VectorType>();
unsigned numIElts = IVT->getNumElements();
if (IType->isExtVectorType())
@@ -1757,8 +1836,10 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
// of the structured initializer list doesn't match exactly,
// because doing so would involve allocating one character
// constant for each string.
- if (!VerifyOnly) {
+ // FIXME: Should we do these checks in verify-only mode too?
+ if (!VerifyOnly)
CheckStringInit(IList->getInit(Index), DeclType, arrayType, SemaRef);
+ if (StructuredList) {
UpdateStructuredListElement(StructuredList, StructuredIndex,
IList->getInit(Index));
StructuredList->resizeInits(SemaRef.Context, StructuredIndex);
@@ -1854,15 +1935,14 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity,
SemaRef.Diag(IList->getBeginLoc(), diag::ext_typecheck_zero_array_size);
}
- DeclType = SemaRef.Context.getConstantArrayType(elementType, maxElements,
- ArrayType::Normal, 0);
+ DeclType = SemaRef.Context.getConstantArrayType(
+ elementType, maxElements, nullptr, ArrayType::Normal, 0);
}
- if (!hadError && VerifyOnly) {
+ if (!hadError) {
// If there are any members of the array that get value-initialized, check
// that is possible. That happens if we know the bound and don't have
// enough elements, or if we're performing an array new with an unknown
// bound.
- // FIXME: This needs to detect holes left by designated initializers too.
if ((maxElementsKnown && elementIndex < maxElements) ||
Entity.isVariableLengthArrayNew())
CheckEmptyInitializable(
@@ -1915,7 +1995,7 @@ void InitListChecker::CheckStructUnionTypes(
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList, unsigned &StructuredIndex,
bool TopLevelObject) {
- RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl();
+ RecordDecl *structDecl = DeclType->castAs<RecordType>()->getDecl();
// If the record is invalid, some of it's members are invalid. To avoid
// confusion, we forgo checking the intializer for the entire record.
@@ -1927,7 +2007,7 @@ void InitListChecker::CheckStructUnionTypes(
}
if (DeclType->isUnionType() && IList->getNumInits() == 0) {
- RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
if (!VerifyOnly)
for (FieldDecl *FD : RD->fields()) {
@@ -1939,8 +2019,9 @@ void InitListChecker::CheckStructUnionTypes(
}
// If there's a default initializer, use it.
- if (isa<CXXRecordDecl>(RD) && cast<CXXRecordDecl>(RD)->hasInClassInitializer()) {
- if (VerifyOnly)
+ if (isa<CXXRecordDecl>(RD) &&
+ cast<CXXRecordDecl>(RD)->hasInClassInitializer()) {
+ if (!StructuredList)
return;
for (RecordDecl::field_iterator FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
@@ -1957,11 +2038,10 @@ void InitListChecker::CheckStructUnionTypes(
for (RecordDecl::field_iterator FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
if (!Field->isUnnamedBitfield()) {
- if (VerifyOnly)
- CheckEmptyInitializable(
- InitializedEntity::InitializeMember(*Field, &Entity),
- IList->getEndLoc());
- else
+ CheckEmptyInitializable(
+ InitializedEntity::InitializeMember(*Field, &Entity),
+ IList->getEndLoc());
+ if (StructuredList)
StructuredList->setInitializedFieldInUnion(*Field);
break;
}
@@ -1987,7 +2067,7 @@ void InitListChecker::CheckStructUnionTypes(
CheckSubElementType(BaseEntity, IList, Base.getType(), Index,
StructuredList, StructuredIndex);
InitializedSomething = true;
- } else if (VerifyOnly) {
+ } else {
CheckEmptyInitializable(BaseEntity, InitLoc);
}
@@ -2002,7 +2082,7 @@ void InitListChecker::CheckStructUnionTypes(
// anything except look at designated initializers; That's okay,
// because an error should get printed out elsewhere. It might be
// worthwhile to skip over the rest of the initializer, though.
- RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
+ RecordDecl *RD = DeclType->castAs<RecordType>()->getDecl();
RecordDecl::field_iterator FieldEnd = RD->field_end();
bool CheckForMissingFields =
!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts());
@@ -2095,7 +2175,7 @@ void InitListChecker::CheckStructUnionTypes(
StructuredList, StructuredIndex);
InitializedSomething = true;
- if (DeclType->isUnionType() && !VerifyOnly) {
+ if (DeclType->isUnionType() && StructuredList) {
// Initialize the first field within the union.
StructuredList->setInitializedFieldInUnion(*Field);
}
@@ -2119,10 +2199,10 @@ void InitListChecker::CheckStructUnionTypes(
}
}
- // Check that any remaining fields can be value-initialized.
- if (VerifyOnly && Field != FieldEnd && !DeclType->isUnionType() &&
+ // Check that any remaining fields can be value-initialized if we're not
+ // building a structured list. (If we are, we'll check this later.)
+ if (!StructuredList && 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() && !Field->hasInClassInitializer())
CheckEmptyInitializable(
@@ -2227,7 +2307,7 @@ class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback {
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<FieldInitializerValidatorCCC>(*this);
+ return std::make_unique<FieldInitializerValidatorCCC>(*this);
}
private:
@@ -2257,7 +2337,9 @@ class FieldInitializerValidatorCCC final : public CorrectionCandidateCallback {
///
/// @param NextField If non-NULL and the first designator in @p DIE is
/// a field, this will be set to the field declaration corresponding
-/// to the field named by the designator.
+/// to the field named by the designator. On input, this is expected to be
+/// the next field that would be initialized in the absence of designation,
+/// if the complete object being initialized is a struct.
///
/// @param NextElementIndex If non-NULL and the first designator in @p
/// DIE is an array designator or GNU array-range designator, this
@@ -2285,6 +2367,29 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
bool FinishSubobjectInit,
bool TopLevelObject) {
if (DesigIdx == DIE->size()) {
+ // C++20 designated initialization can result in direct-list-initialization
+ // of the designated subobject. This is the only way that we can end up
+ // performing direct initialization as part of aggregate initialization, so
+ // it needs special handling.
+ if (DIE->isDirectInit()) {
+ Expr *Init = DIE->getInit();
+ assert(isa<InitListExpr>(Init) &&
+ "designator result in direct non-list initialization?");
+ InitializationKind Kind = InitializationKind::CreateDirectList(
+ DIE->getBeginLoc(), Init->getBeginLoc(), Init->getEndLoc());
+ InitializationSequence Seq(SemaRef, Entity, Kind, Init,
+ /*TopLevelOfInitList*/ true);
+ if (StructuredList) {
+ ExprResult Result = VerifyOnly
+ ? getDummyInit()
+ : Seq.Perform(SemaRef, Entity, Kind, Init);
+ UpdateStructuredListElement(StructuredList, StructuredIndex,
+ Result.get());
+ }
+ ++Index;
+ return !Seq;
+ }
+
// Check the actual initialization for the designated object type.
bool prevHadError = hadError;
@@ -2308,14 +2413,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
DesignatedInitExpr::Designator *D = DIE->getDesignator(DesigIdx);
bool IsFirstDesignator = (DesigIdx == 0);
- if (!VerifyOnly) {
- assert((IsFirstDesignator || StructuredList) &&
- "Need a non-designated initializer list to start from");
-
+ if (IsFirstDesignator ? FullyStructuredList : StructuredList) {
// Determine the structural initializer list that corresponds to the
// current subobject.
if (IsFirstDesignator)
- StructuredList = SyntacticToSemantic.lookup(IList);
+ StructuredList = FullyStructuredList;
else {
Expr *ExistingInit = StructuredIndex < StructuredList->getNumInits() ?
StructuredList->getInit(StructuredIndex) : nullptr;
@@ -2329,48 +2431,42 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
else if (InitListExpr *Result = dyn_cast<InitListExpr>(ExistingInit))
StructuredList = Result;
else {
- if (DesignatedInitUpdateExpr *E =
- dyn_cast<DesignatedInitUpdateExpr>(ExistingInit))
- StructuredList = E->getUpdater();
- else {
- DesignatedInitUpdateExpr *DIUE = new (SemaRef.Context)
- DesignatedInitUpdateExpr(SemaRef.Context, D->getBeginLoc(),
- ExistingInit, DIE->getEndLoc());
- StructuredList->updateInit(SemaRef.Context, StructuredIndex, DIUE);
- StructuredList = DIUE->getUpdater();
- }
-
- // We need to check on source range validity because the previous
- // initializer does not have to be an explicit initializer. e.g.,
+ // We are creating an initializer list that initializes the
+ // subobjects of the current object, but there was already an
+ // initialization that completely initialized the current
+ // subobject, e.g., by a compound literal:
//
- // struct P { int a, b; };
- // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 };
+ // struct X { int a, b; };
+ // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
//
- // There is an overwrite taking place because the first braced initializer
- // list "{ .a = 2 }" already provides value for .p.b (which is zero).
- if (ExistingInit->getSourceRange().isValid()) {
- // We are creating an initializer list that initializes the
- // subobjects of the current object, but there was already an
- // initialization that completely initialized the current
- // subobject, e.g., by a compound literal:
- //
- // struct X { int a, b; };
- // struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
- //
- // Here, xs[0].a == 0 and xs[0].b == 3, since the second,
- // designated initializer re-initializes the whole
- // subobject [0], overwriting previous initializers.
- SemaRef.Diag(D->getBeginLoc(),
- diag::warn_subobject_initializer_overrides)
- << SourceRange(D->getBeginLoc(), DIE->getEndLoc());
-
- SemaRef.Diag(ExistingInit->getBeginLoc(),
- diag::note_previous_initializer)
- << /*FIXME:has side effects=*/0 << ExistingInit->getSourceRange();
+ // Here, xs[0].a == 1 and xs[0].b == 3, since the second,
+ // designated initializer re-initializes only its current object
+ // subobject [0].b.
+ diagnoseInitOverride(ExistingInit,
+ SourceRange(D->getBeginLoc(), DIE->getEndLoc()),
+ /*FullyOverwritten=*/false);
+
+ if (!VerifyOnly) {
+ if (DesignatedInitUpdateExpr *E =
+ dyn_cast<DesignatedInitUpdateExpr>(ExistingInit))
+ StructuredList = E->getUpdater();
+ else {
+ DesignatedInitUpdateExpr *DIUE = new (SemaRef.Context)
+ DesignatedInitUpdateExpr(SemaRef.Context, D->getBeginLoc(),
+ ExistingInit, DIE->getEndLoc());
+ StructuredList->updateInit(SemaRef.Context, StructuredIndex, DIUE);
+ StructuredList = DIUE->getUpdater();
+ }
+ } else {
+ // We don't need to track the structured representation of a
+ // designated init update of an already-fully-initialized object in
+ // verify-only mode. The only reason we would need the structure is
+ // to determine where the uninitialized "holes" are, and in this
+ // case, we know there aren't any and we can't introduce any.
+ StructuredList = nullptr;
}
}
}
- assert(StructuredList && "Expected a structured initializer list");
}
if (D->isFieldDesignator()) {
@@ -2453,10 +2549,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
}
}
- unsigned FieldIndex = 0;
-
+ unsigned NumBases = 0;
if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
- FieldIndex = CXXRD->getNumBases();
+ NumBases = CXXRD->getNumBases();
+
+ unsigned FieldIndex = NumBases;
for (auto *FI : RT->getDecl()->fields()) {
if (FI->isUnnamedBitfield())
@@ -2475,7 +2572,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// the initializer list.
if (RT->getDecl()->isUnion()) {
FieldIndex = 0;
- if (!VerifyOnly) {
+ if (StructuredList) {
FieldDecl *CurrentField = StructuredList->getInitializedFieldInUnion();
if (CurrentField && !declaresSameEntity(CurrentField, *Field)) {
assert(StructuredList->getNumInits() == 1
@@ -2484,13 +2581,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
Expr *ExistingInit = StructuredList->getInit(0);
if (ExistingInit) {
// We're about to throw away an initializer, emit warning.
- SemaRef.Diag(D->getFieldLoc(),
- diag::warn_initializer_overrides)
- << D->getSourceRange();
- SemaRef.Diag(ExistingInit->getBeginLoc(),
- diag::note_previous_initializer)
- << /*FIXME:has side effects=*/0
- << ExistingInit->getSourceRange();
+ diagnoseInitOverride(
+ ExistingInit, SourceRange(D->getBeginLoc(), DIE->getEndLoc()));
}
// remove existing initializer
@@ -2513,16 +2605,63 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
return true;
}
- if (!VerifyOnly) {
- // Update the designator with the field declaration.
- D->setField(*Field);
+ // C++20 [dcl.init.list]p3:
+ // The ordered identifiers in the designators of the designated-
+ // initializer-list shall form a subsequence of the ordered identifiers
+ // in the direct non-static data members of T.
+ //
+ // Note that this is not a condition on forming the aggregate
+ // initialization, only on actually performing initialization,
+ // so it is not checked in VerifyOnly mode.
+ //
+ // FIXME: This is the only reordering diagnostic we produce, and it only
+ // catches cases where we have a top-level field designator that jumps
+ // backwards. This is the only such case that is reachable in an
+ // otherwise-valid C++20 program, so is the only case that's required for
+ // conformance, but for consistency, we should diagnose all the other
+ // cases where a designator takes us backwards too.
+ if (IsFirstDesignator && !VerifyOnly && SemaRef.getLangOpts().CPlusPlus &&
+ NextField &&
+ (*NextField == RT->getDecl()->field_end() ||
+ (*NextField)->getFieldIndex() > Field->getFieldIndex() + 1)) {
+ // Find the field that we just initialized.
+ FieldDecl *PrevField = nullptr;
+ for (auto FI = RT->getDecl()->field_begin();
+ FI != RT->getDecl()->field_end(); ++FI) {
+ if (FI->isUnnamedBitfield())
+ continue;
+ if (*NextField != RT->getDecl()->field_end() &&
+ declaresSameEntity(*FI, **NextField))
+ break;
+ PrevField = *FI;
+ }
- // Make sure that our non-designated initializer list has space
- // for a subobject corresponding to this field.
- if (FieldIndex >= StructuredList->getNumInits())
- StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1);
+ if (PrevField &&
+ PrevField->getFieldIndex() > KnownField->getFieldIndex()) {
+ SemaRef.Diag(DIE->getBeginLoc(), diag::ext_designated_init_reordered)
+ << KnownField << PrevField << DIE->getSourceRange();
+
+ unsigned OldIndex = NumBases + PrevField->getFieldIndex();
+ if (StructuredList && OldIndex <= StructuredList->getNumInits()) {
+ if (Expr *PrevInit = StructuredList->getInit(OldIndex)) {
+ SemaRef.Diag(PrevInit->getBeginLoc(),
+ diag::note_previous_field_init)
+ << PrevField << PrevInit->getSourceRange();
+ }
+ }
+ }
}
+
+ // Update the designator with the field declaration.
+ if (!VerifyOnly)
+ D->setField(*Field);
+
+ // Make sure that our non-designated initializer list has space
+ // for a subobject corresponding to this field.
+ if (StructuredList && FieldIndex >= StructuredList->getNumInits())
+ StructuredList->resizeInits(SemaRef.Context, FieldIndex + 1);
+
// This designator names a flexible array member.
if (Field->getType()->isIncompleteArrayType()) {
bool Invalid = false;
@@ -2707,7 +2846,13 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
DesignatedEndIndex.setIsUnsigned(true);
}
- if (!VerifyOnly && StructuredList->isStringLiteralInit()) {
+ bool IsStringLiteralInitUpdate =
+ StructuredList && StructuredList->isStringLiteralInit();
+ if (IsStringLiteralInitUpdate && VerifyOnly) {
+ // We're just verifying an update to a string literal init. We don't need
+ // to split the string up into individual characters to do that.
+ StructuredList = nullptr;
+ } else if (IsStringLiteralInitUpdate) {
// We're modifying a string literal init; we have to decompose the string
// so we can modify the individual characters.
ASTContext &Context = SemaRef.Context;
@@ -2767,7 +2912,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// Make sure that our non-designated initializer list has space
// for a subobject corresponding to this array element.
- if (!VerifyOnly &&
+ if (StructuredList &&
DesignatedEndIndex.getZExtValue() >= StructuredList->getNumInits())
StructuredList->resizeInits(SemaRef.Context,
DesignatedEndIndex.getZExtValue() + 1);
@@ -2829,12 +2974,11 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
unsigned StructuredIndex,
SourceRange InitRange,
bool IsFullyOverwritten) {
- if (VerifyOnly)
- return nullptr; // No structured list in verification-only mode.
- Expr *ExistingInit = nullptr;
if (!StructuredList)
- ExistingInit = SyntacticToSemantic.lookup(IList);
- else if (StructuredIndex < StructuredList->getNumInits())
+ return nullptr;
+
+ Expr *ExistingInit = nullptr;
+ if (StructuredIndex < StructuredList->getNumInits())
ExistingInit = StructuredList->getInit(StructuredIndex);
if (InitListExpr *Result = dyn_cast_or_null<InitListExpr>(ExistingInit))
@@ -2853,21 +2997,46 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
// We are creating an initializer list that initializes the
// subobjects of the current object, but there was already an
// initialization that completely initialized the current
- // subobject, e.g., by a compound literal:
+ // subobject:
//
// struct X { int a, b; };
+ // struct X xs[] = { [0] = { 1, 2 }, [0].b = 3 };
+ //
+ // Here, xs[0].a == 1 and xs[0].b == 3, since the second,
+ // designated initializer overwrites the [0].b initializer
+ // from the prior initialization.
+ //
+ // When the existing initializer is an expression rather than an
+ // initializer list, we cannot decompose and update it in this way.
+ // For example:
+ //
// struct X xs[] = { [0] = (struct X) { 1, 2 }, [0].b = 3 };
//
- // Here, xs[0].a == 0 and xs[0].b == 3, since the second,
- // designated initializer re-initializes the whole
- // subobject [0], overwriting previous initializers.
- SemaRef.Diag(InitRange.getBegin(),
- diag::warn_subobject_initializer_overrides)
- << InitRange;
- SemaRef.Diag(ExistingInit->getBeginLoc(), diag::note_previous_initializer)
- << /*FIXME:has side effects=*/0 << ExistingInit->getSourceRange();
+ // This case is handled by CheckDesignatedInitializer.
+ diagnoseInitOverride(ExistingInit, InitRange);
}
+ unsigned ExpectedNumInits = 0;
+ if (Index < IList->getNumInits()) {
+ if (auto *Init = dyn_cast_or_null<InitListExpr>(IList->getInit(Index)))
+ ExpectedNumInits = Init->getNumInits();
+ else
+ ExpectedNumInits = IList->getNumInits() - Index;
+ }
+
+ InitListExpr *Result =
+ createInitListExpr(CurrentObjectType, InitRange, ExpectedNumInits);
+
+ // Link this new initializer list into the structured initializer
+ // lists.
+ StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result);
+ return Result;
+}
+
+InitListExpr *
+InitListChecker::createInitListExpr(QualType CurrentObjectType,
+ SourceRange InitRange,
+ unsigned ExpectedNumInits) {
InitListExpr *Result
= new (SemaRef.Context) InitListExpr(SemaRef.Context,
InitRange.getBegin(), None,
@@ -2880,17 +3049,6 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
// Pre-allocate storage for the structured initializer list.
unsigned NumElements = 0;
- unsigned NumInits = 0;
- bool GotNumInits = false;
- if (!StructuredList) {
- NumInits = IList->getNumInits();
- GotNumInits = true;
- } else if (Index < IList->getNumInits()) {
- if (InitListExpr *SubList = dyn_cast<InitListExpr>(IList->getInit(Index))) {
- NumInits = SubList->getNumInits();
- GotNumInits = true;
- }
- }
if (const ArrayType *AType
= SemaRef.Context.getAsArrayType(CurrentObjectType)) {
@@ -2898,30 +3056,17 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
NumElements = CAType->getSize().getZExtValue();
// Simple heuristic so that we don't allocate a very large
// initializer with many empty entries at the end.
- if (GotNumInits && NumElements > NumInits)
+ if (NumElements > ExpectedNumInits)
NumElements = 0;
}
- } else if (const VectorType *VType = CurrentObjectType->getAs<VectorType>())
+ } else if (const VectorType *VType = CurrentObjectType->getAs<VectorType>()) {
NumElements = VType->getNumElements();
- else if (const RecordType *RType = CurrentObjectType->getAs<RecordType>()) {
- RecordDecl *RDecl = RType->getDecl();
- if (RDecl->isUnion())
- NumElements = 1;
- else
- NumElements = std::distance(RDecl->field_begin(), RDecl->field_end());
+ } else if (CurrentObjectType->isRecordType()) {
+ NumElements = numStructUnionElements(CurrentObjectType);
}
Result->reserveInits(SemaRef.Context, NumElements);
- // Link this new initializer list into the structured initializer
- // lists.
- if (StructuredList)
- StructuredList->updateInit(SemaRef.Context, StructuredIndex, Result);
- else {
- Result->setSyntacticForm(IList);
- SyntacticToSemantic[IList] = Result;
- }
-
return Result;
}
@@ -2937,24 +3082,23 @@ void InitListChecker::UpdateStructuredListElement(InitListExpr *StructuredList,
if (Expr *PrevInit = StructuredList->updateInit(SemaRef.Context,
StructuredIndex, expr)) {
// This initializer overwrites a previous initializer. Warn.
- // We need to check on source range validity because the previous
- // initializer does not have to be an explicit initializer.
- // struct P { int a, b; };
- // struct PP { struct P p } l = { { .a = 2 }, .p.b = 3 };
- // There is an overwrite taking place because the first braced initializer
- // list "{ .a = 2 }' already provides value for .p.b (which is zero).
- if (PrevInit->getSourceRange().isValid()) {
- SemaRef.Diag(expr->getBeginLoc(), diag::warn_initializer_overrides)
- << expr->getSourceRange();
-
- SemaRef.Diag(PrevInit->getBeginLoc(), diag::note_previous_initializer)
- << /*FIXME:has side effects=*/0 << PrevInit->getSourceRange();
- }
+ diagnoseInitOverride(PrevInit, expr->getSourceRange());
}
++StructuredIndex;
}
+/// Determine whether we can perform aggregate initialization for the purposes
+/// of overload resolution.
+bool Sema::CanPerformAggregateInitializationForOverloadResolution(
+ const InitializedEntity &Entity, InitListExpr *From) {
+ QualType Type = Entity.getType();
+ InitListChecker Check(*this, Entity, From, Type, /*VerifyOnly=*/true,
+ /*TreatUnavailableAsInvalid=*/false,
+ /*InOverloadResolution=*/true);
+ return !Check.HadError();
+}
+
/// Check that the given Index expression is a valid array designator
/// value. This is essentially just a wrapper around
/// VerifyIntegerConstantExpression that also checks for negative values
@@ -2980,7 +3124,7 @@ CheckArrayDesignatorExpr(Sema &S, Expr *Index, llvm::APSInt &Value) {
}
ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
- SourceLocation Loc,
+ SourceLocation EqualOrColonLoc,
bool GNUSyntax,
ExprResult Init) {
typedef DesignatedInitExpr::Designator ASTDesignator;
@@ -3065,17 +3209,9 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
// Clear out the expressions within the designation.
Desig.ClearExprs(*this);
- DesignatedInitExpr *DIE
- = DesignatedInitExpr::Create(Context,
- Designators,
- InitExpressions, Loc, GNUSyntax,
- Init.getAs<Expr>());
-
- if (!getLangOpts().C99)
- Diag(DIE->getBeginLoc(), diag::ext_designated_init)
- << DIE->getSourceRange();
-
- return DIE;
+ return DesignatedInitExpr::Create(Context, Designators, InitExpressions,
+ EqualOrColonLoc, GNUSyntax,
+ Init.getAs<Expr>());
}
//===----------------------------------------------------------------------===//
@@ -3691,9 +3827,10 @@ static bool TryInitializerListConstruction(Sema &S,
// Try initializing a temporary array from the init list.
QualType ArrayType = S.Context.getConstantArrayType(
- E.withConst(), llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
- List->getNumInits()),
- clang::ArrayType::Normal, 0);
+ E.withConst(),
+ llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
+ List->getNumInits()),
+ nullptr, clang::ArrayType::Normal, 0);
InitializedEntity HiddenArray =
InitializedEntity::InitializeTemporary(ArrayType);
InitializationKind Kind = InitializationKind::CreateDirectList(
@@ -4070,7 +4207,7 @@ static void TryReferenceListInitialization(Sema &S,
}
QualType DestType = Entity.getType();
- QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
+ QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType();
Qualifiers T1Quals;
QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals);
@@ -4092,10 +4229,10 @@ static void TryReferenceListInitialization(Sema &S,
return;
SourceLocation DeclLoc = Initializer->getBeginLoc();
- bool dummy1, dummy2, dummy3;
+ bool dummy1, dummy2, dummy3, dummy4;
Sema::ReferenceCompareResult RefRelationship
= S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1,
- dummy2, dummy3);
+ dummy2, dummy3, dummy4);
if (RefRelationship >= Sema::Ref_Related) {
// Try to bind the reference here.
TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
@@ -4327,7 +4464,7 @@ static OverloadingResult TryRefInitWithConversionFunction(
Expr *Initializer, bool AllowRValues, bool IsLValueRef,
InitializationSequence &Sequence) {
QualType DestType = Entity.getType();
- QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
+ QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType();
QualType T1 = cv1T1.getUnqualifiedType();
QualType cv2T2 = Initializer->getType();
QualType T2 = cv2T2.getUnqualifiedType();
@@ -4335,13 +4472,15 @@ static OverloadingResult TryRefInitWithConversionFunction(
bool DerivedToBase;
bool ObjCConversion;
bool ObjCLifetimeConversion;
- assert(!S.CompareReferenceRelationship(Initializer->getBeginLoc(), T1, T2,
- DerivedToBase, ObjCConversion,
- ObjCLifetimeConversion) &&
+ bool FunctionConversion;
+ assert(!S.CompareReferenceRelationship(
+ Initializer->getBeginLoc(), T1, T2, DerivedToBase, ObjCConversion,
+ ObjCLifetimeConversion, FunctionConversion) &&
"Must have incompatible references when binding via conversion");
(void)DerivedToBase;
(void)ObjCConversion;
(void)ObjCLifetimeConversion;
+ (void)FunctionConversion;
// Build the candidate set directly in the initialization sequence
// structure, so that it will persist if we fail.
@@ -4468,10 +4607,11 @@ static OverloadingResult TryRefInitWithConversionFunction(
bool NewDerivedToBase = false;
bool NewObjCConversion = false;
bool NewObjCLifetimeConversion = false;
- Sema::ReferenceCompareResult NewRefRelationship
- = S.CompareReferenceRelationship(DeclLoc, T1, cv3T3,
- NewDerivedToBase, NewObjCConversion,
- NewObjCLifetimeConversion);
+ bool NewFunctionConversion = false;
+ Sema::ReferenceCompareResult NewRefRelationship =
+ S.CompareReferenceRelationship(
+ DeclLoc, T1, cv3T3, NewDerivedToBase, NewObjCConversion,
+ NewObjCLifetimeConversion, NewFunctionConversion);
// Add the final conversion sequence, if necessary.
if (NewRefRelationship == Sema::Ref_Incompatible) {
@@ -4505,6 +4645,8 @@ static OverloadingResult TryRefInitWithConversionFunction(
Sequence.AddDerivedToBaseCastStep(cv1T1, VK);
else if (NewObjCConversion)
Sequence.AddObjCObjectConversionStep(cv1T1);
+ else if (NewFunctionConversion)
+ Sequence.AddQualificationConversionStep(cv1T1, VK);
return OR_Success;
}
@@ -4520,7 +4662,7 @@ static void TryReferenceInitialization(Sema &S,
Expr *Initializer,
InitializationSequence &Sequence) {
QualType DestType = Entity.getType();
- QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType();
+ QualType cv1T1 = DestType->castAs<ReferenceType>()->getPointeeType();
Qualifiers T1Quals;
QualType T1 = S.Context.getUnqualifiedArrayType(cv1T1, T1Quals);
QualType cv2T2 = Initializer->getType();
@@ -4564,10 +4706,11 @@ static void TryReferenceInitializationCore(Sema &S,
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
+ bool FunctionConversion = false;
Expr::Classification InitCategory = Initializer->Classify(S.Context);
- Sema::ReferenceCompareResult RefRelationship
- = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion);
+ Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(
+ DeclLoc, cv1T1, cv2T2, DerivedToBase, ObjCConversion,
+ ObjCLifetimeConversion, FunctionConversion);
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression of type
@@ -4598,6 +4741,8 @@ static void TryReferenceInitializationCore(Sema &S,
Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue);
else if (ObjCConversion)
Sequence.AddObjCObjectConversionStep(cv1T1);
+ else if (FunctionConversion)
+ Sequence.AddQualificationConversionStep(cv1T1, VK_LValue);
// We only create a temporary here when binding a reference to a
// bit-field or vector element. Those cases are't supposed to be
@@ -6233,8 +6378,11 @@ PerformConstructorInitialization(Sema &S,
// 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);
+ Constructor->isTrivial() && !Constructor->isUsed(false)) {
+ S.runWithSufficientStackSpace(Loc, [&] {
+ S.DefineImplicitDefaultConstructor(Loc, Constructor);
+ });
+ }
}
ExprResult CurInit((Expr *)nullptr);
@@ -6505,6 +6653,7 @@ struct IndirectLocalPathEntry {
VarInit,
LValToRVal,
LifetimeBoundCall,
+ GslPointerInit
} Kind;
Expr *E;
const Decl *D = nullptr;
@@ -6543,11 +6692,138 @@ static bool pathContainsInit(IndirectLocalPath &Path) {
static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Expr *Init, LocalVisitor Visit,
- bool RevisitSubinits);
+ bool RevisitSubinits,
+ bool EnableLifetimeWarnings);
static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
Expr *Init, ReferenceKind RK,
- LocalVisitor Visit);
+ LocalVisitor Visit,
+ bool EnableLifetimeWarnings);
+
+template <typename T> static bool isRecordWithAttr(QualType Type) {
+ if (auto *RD = Type->getAsCXXRecordDecl())
+ return RD->hasAttr<T>();
+ return false;
+}
+
+// Decl::isInStdNamespace will return false for iterators in some STL
+// implementations due to them being defined in a namespace outside of the std
+// namespace.
+static bool isInStlNamespace(const Decl *D) {
+ const DeclContext *DC = D->getDeclContext();
+ if (!DC)
+ return false;
+ if (const auto *ND = dyn_cast<NamespaceDecl>(DC))
+ if (const IdentifierInfo *II = ND->getIdentifier()) {
+ StringRef Name = II->getName();
+ if (Name.size() >= 2 && Name.front() == '_' &&
+ (Name[1] == '_' || isUppercase(Name[1])))
+ return true;
+ }
+
+ return DC->isStdNamespace();
+}
+
+static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
+ if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
+ if (isRecordWithAttr<PointerAttr>(Conv->getConversionType()))
+ return true;
+ if (!isInStlNamespace(Callee->getParent()))
+ return false;
+ if (!isRecordWithAttr<PointerAttr>(Callee->getThisObjectType()) &&
+ !isRecordWithAttr<OwnerAttr>(Callee->getThisObjectType()))
+ return false;
+ if (Callee->getReturnType()->isPointerType() ||
+ isRecordWithAttr<PointerAttr>(Callee->getReturnType())) {
+ if (!Callee->getIdentifier())
+ return false;
+ return llvm::StringSwitch<bool>(Callee->getName())
+ .Cases("begin", "rbegin", "cbegin", "crbegin", true)
+ .Cases("end", "rend", "cend", "crend", true)
+ .Cases("c_str", "data", "get", true)
+ // Map and set types.
+ .Cases("find", "equal_range", "lower_bound", "upper_bound", true)
+ .Default(false);
+ } else if (Callee->getReturnType()->isReferenceType()) {
+ if (!Callee->getIdentifier()) {
+ auto OO = Callee->getOverloadedOperator();
+ return OO == OverloadedOperatorKind::OO_Subscript ||
+ OO == OverloadedOperatorKind::OO_Star;
+ }
+ return llvm::StringSwitch<bool>(Callee->getName())
+ .Cases("front", "back", "at", "top", "value", true)
+ .Default(false);
+ }
+ return false;
+}
+
+static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
+ if (!FD->getIdentifier() || FD->getNumParams() != 1)
+ return false;
+ const auto *RD = FD->getParamDecl(0)->getType()->getPointeeCXXRecordDecl();
+ if (!FD->isInStdNamespace() || !RD || !RD->isInStdNamespace())
+ return false;
+ if (!isRecordWithAttr<PointerAttr>(QualType(RD->getTypeForDecl(), 0)) &&
+ !isRecordWithAttr<OwnerAttr>(QualType(RD->getTypeForDecl(), 0)))
+ return false;
+ if (FD->getReturnType()->isPointerType() ||
+ isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
+ return llvm::StringSwitch<bool>(FD->getName())
+ .Cases("begin", "rbegin", "cbegin", "crbegin", true)
+ .Cases("end", "rend", "cend", "crend", true)
+ .Case("data", true)
+ .Default(false);
+ } else if (FD->getReturnType()->isReferenceType()) {
+ return llvm::StringSwitch<bool>(FD->getName())
+ .Cases("get", "any_cast", true)
+ .Default(false);
+ }
+ return false;
+}
+
+static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
+ LocalVisitor Visit) {
+ auto VisitPointerArg = [&](const Decl *D, Expr *Arg) {
+ // We are not interested in the temporary base objects of gsl Pointers:
+ // Temp().ptr; // Here ptr might not dangle.
+ if (isa<MemberExpr>(Arg->IgnoreImpCasts()))
+ return;
+ Path.push_back({IndirectLocalPathEntry::GslPointerInit, Arg, D});
+ if (Arg->isGLValue())
+ visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,
+ Visit,
+ /*EnableLifetimeWarnings=*/true);
+ else
+ visitLocalsRetainedByInitializer(Path, Arg, Visit, true,
+ /*EnableLifetimeWarnings=*/true);
+ Path.pop_back();
+ };
+
+ if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) {
+ const auto *MD = cast_or_null<CXXMethodDecl>(MCE->getDirectCallee());
+ if (MD && shouldTrackImplicitObjectArg(MD))
+ VisitPointerArg(MD, MCE->getImplicitObjectArgument());
+ return;
+ } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(Call)) {
+ FunctionDecl *Callee = OCE->getDirectCallee();
+ if (Callee && Callee->isCXXInstanceMember() &&
+ shouldTrackImplicitObjectArg(cast<CXXMethodDecl>(Callee)))
+ VisitPointerArg(Callee, OCE->getArg(0));
+ return;
+ } else if (auto *CE = dyn_cast<CallExpr>(Call)) {
+ FunctionDecl *Callee = CE->getDirectCallee();
+ if (Callee && shouldTrackFirstArgument(Callee))
+ VisitPointerArg(Callee, CE->getArg(0));
+ return;
+ }
+
+ if (auto *CCE = dyn_cast<CXXConstructExpr>(Call)) {
+ const auto *Ctor = CCE->getConstructor();
+ const CXXRecordDecl *RD = Ctor->getParent();
+ if (CCE->getNumArgs() > 0 && RD->hasAttr<PointerAttr>())
+ VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0]);
+ }
+}
static bool implicitObjectParamIsLifetimeBound(const FunctionDecl *FD) {
const TypeSourceInfo *TSI = FD->getTypeSourceInfo();
@@ -6594,9 +6870,11 @@ static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
Path.push_back({IndirectLocalPathEntry::LifetimeBoundCall, Arg, D});
if (Arg->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,
- Visit);
+ Visit,
+ /*EnableLifetimeWarnings=*/false);
else
- visitLocalsRetainedByInitializer(Path, Arg, Visit, true);
+ visitLocalsRetainedByInitializer(Path, Arg, Visit, true,
+ /*EnableLifetimeWarnings=*/false);
Path.pop_back();
};
@@ -6615,7 +6893,8 @@ static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call,
/// glvalue expression \c Init.
static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
Expr *Init, ReferenceKind RK,
- LocalVisitor Visit) {
+ LocalVisitor Visit,
+ bool EnableLifetimeWarnings) {
RevertToOldSizeRAII RAII(Path);
// Walk past any constructs which we can lifetime-extend across.
@@ -6652,7 +6931,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
else
// We can't lifetime extend through this but we might still find some
// retained temporaries.
- return visitLocalsRetainedByInitializer(Path, Init, Visit, true);
+ return visitLocalsRetainedByInitializer(Path, Init, Visit, true,
+ EnableLifetimeWarnings);
}
// Step into CXXDefaultInitExprs so we can diagnose cases where a
@@ -6667,11 +6947,14 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) {
if (Visit(Path, Local(MTE), RK))
visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(), Visit,
- true);
+ true, EnableLifetimeWarnings);
}
- if (isa<CallExpr>(Init))
+ if (isa<CallExpr>(Init)) {
+ if (EnableLifetimeWarnings)
+ handleGslAnnotatedTypes(Path, Init, Visit);
return visitLifetimeBoundArguments(Path, Init, Visit);
+ }
switch (Init->getStmtClass()) {
case Stmt::DeclRefExprClass: {
@@ -6690,7 +6973,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
} else if (VD->getInit() && !isVarOnPath(Path, VD)) {
Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD});
visitLocalsRetainedByReferenceBinding(Path, VD->getInit(),
- RK_ReferenceBinding, Visit);
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
}
}
break;
@@ -6702,13 +6986,15 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
// handling all sorts of rvalues passed to a unary operator.
const UnaryOperator *U = cast<UnaryOperator>(Init);
if (U->getOpcode() == UO_Deref)
- visitLocalsRetainedByInitializer(Path, U->getSubExpr(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, U->getSubExpr(), Visit, true,
+ EnableLifetimeWarnings);
break;
}
case Stmt::OMPArraySectionExprClass: {
- visitLocalsRetainedByInitializer(
- Path, cast<OMPArraySectionExpr>(Init)->getBase(), Visit, true);
+ visitLocalsRetainedByInitializer(Path,
+ cast<OMPArraySectionExpr>(Init)->getBase(),
+ Visit, true, EnableLifetimeWarnings);
break;
}
@@ -6716,9 +7002,11 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
case Stmt::BinaryConditionalOperatorClass: {
auto *C = cast<AbstractConditionalOperator>(Init);
if (!C->getTrueExpr()->getType()->isVoidType())
- visitLocalsRetainedByReferenceBinding(Path, C->getTrueExpr(), RK, Visit);
+ visitLocalsRetainedByReferenceBinding(Path, C->getTrueExpr(), RK, Visit,
+ EnableLifetimeWarnings);
if (!C->getFalseExpr()->getType()->isVoidType())
- visitLocalsRetainedByReferenceBinding(Path, C->getFalseExpr(), RK, Visit);
+ visitLocalsRetainedByReferenceBinding(Path, C->getFalseExpr(), RK, Visit,
+ EnableLifetimeWarnings);
break;
}
@@ -6733,7 +7021,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
/// the prvalue expression \c Init.
static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Expr *Init, LocalVisitor Visit,
- bool RevisitSubinits) {
+ bool RevisitSubinits,
+ bool EnableLifetimeWarnings) {
RevertToOldSizeRAII RAII(Path);
Expr *Old;
@@ -6773,15 +7062,17 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
if (VD && VD->getType().isConstQualified() && VD->getInit() &&
!isVarOnPath(Path, VD)) {
Path.push_back({IndirectLocalPathEntry::VarInit, DRE, VD});
- visitLocalsRetainedByInitializer(Path, VD->getInit(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, VD->getInit(), Visit, true,
+ EnableLifetimeWarnings);
}
} else if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L)) {
if (MTE->getType().isConstQualified())
visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(),
- Visit, true);
+ Visit, true,
+ EnableLifetimeWarnings);
}
return false;
- });
+ }, EnableLifetimeWarnings);
// We assume that objects can be retained by pointers cast to integers,
// but not if the integer is cast to floating-point type or to _Complex.
@@ -6811,7 +7102,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
// lvalue.
Path.push_back({IndirectLocalPathEntry::AddressOf, CE});
return visitLocalsRetainedByReferenceBinding(Path, CE->getSubExpr(),
- RK_ReferenceBinding, Visit);
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
default:
return;
@@ -6826,7 +7118,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
// lifetime of the array exactly like binding a reference to a temporary.
if (auto *ILE = dyn_cast<CXXStdInitializerListExpr>(Init))
return visitLocalsRetainedByReferenceBinding(Path, ILE->getSubExpr(),
- RK_StdInitializerList, Visit);
+ RK_StdInitializerList, Visit,
+ EnableLifetimeWarnings);
if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
// We already visited the elements of this initializer list while
@@ -6837,12 +7130,14 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
if (ILE->isTransparent())
return visitLocalsRetainedByInitializer(Path, ILE->getInit(0), Visit,
- RevisitSubinits);
+ RevisitSubinits,
+ EnableLifetimeWarnings);
if (ILE->getType()->isArrayType()) {
for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I)
visitLocalsRetainedByInitializer(Path, ILE->getInit(I), Visit,
- RevisitSubinits);
+ RevisitSubinits,
+ EnableLifetimeWarnings);
return;
}
@@ -6855,12 +7150,14 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
if (RD->isUnion() && ILE->getInitializedFieldInUnion() &&
ILE->getInitializedFieldInUnion()->getType()->isReferenceType())
visitLocalsRetainedByReferenceBinding(Path, ILE->getInit(0),
- RK_ReferenceBinding, Visit);
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
else {
unsigned Index = 0;
for (; Index < RD->getNumBases() && Index < ILE->getNumInits(); ++Index)
visitLocalsRetainedByInitializer(Path, ILE->getInit(Index), Visit,
- RevisitSubinits);
+ RevisitSubinits,
+ EnableLifetimeWarnings);
for (const auto *I : RD->fields()) {
if (Index >= ILE->getNumInits())
break;
@@ -6869,13 +7166,15 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Expr *SubInit = ILE->getInit(Index);
if (I->getType()->isReferenceType())
visitLocalsRetainedByReferenceBinding(Path, SubInit,
- RK_ReferenceBinding, Visit);
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
else
// This might be either aggregate-initialization of a member or
// initialization of a std::initializer_list object. Regardless,
// we should recursively lifetime-extend that initializer.
visitLocalsRetainedByInitializer(Path, SubInit, Visit,
- RevisitSubinits);
+ RevisitSubinits,
+ EnableLifetimeWarnings);
++Index;
}
}
@@ -6891,14 +7190,18 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
continue;
if (E->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, E, RK_ReferenceBinding,
- Visit);
+ Visit, EnableLifetimeWarnings);
else
- visitLocalsRetainedByInitializer(Path, E, Visit, true);
+ visitLocalsRetainedByInitializer(Path, E, Visit, true,
+ EnableLifetimeWarnings);
}
}
- if (isa<CallExpr>(Init) || isa<CXXConstructExpr>(Init))
+ if (isa<CallExpr>(Init) || isa<CXXConstructExpr>(Init)) {
+ if (EnableLifetimeWarnings)
+ handleGslAnnotatedTypes(Path, Init, Visit);
return visitLifetimeBoundArguments(Path, Init, Visit);
+ }
switch (Init->getStmtClass()) {
case Stmt::UnaryOperatorClass: {
@@ -6914,7 +7217,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
Path.push_back({IndirectLocalPathEntry::AddressOf, UO});
visitLocalsRetainedByReferenceBinding(Path, UO->getSubExpr(),
- RK_ReferenceBinding, Visit);
+ RK_ReferenceBinding, Visit,
+ EnableLifetimeWarnings);
}
break;
}
@@ -6927,9 +7231,11 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
break;
if (BO->getLHS()->getType()->isPointerType())
- visitLocalsRetainedByInitializer(Path, BO->getLHS(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, BO->getLHS(), Visit, true,
+ EnableLifetimeWarnings);
else if (BO->getRHS()->getType()->isPointerType())
- visitLocalsRetainedByInitializer(Path, BO->getRHS(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, BO->getRHS(), Visit, true,
+ EnableLifetimeWarnings);
break;
}
@@ -6939,9 +7245,11 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
// In C++, we can have a throw-expression operand, which has 'void' type
// and isn't interesting from a lifetime perspective.
if (!C->getTrueExpr()->getType()->isVoidType())
- visitLocalsRetainedByInitializer(Path, C->getTrueExpr(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, C->getTrueExpr(), Visit, true,
+ EnableLifetimeWarnings);
if (!C->getFalseExpr()->getType()->isVoidType())
- visitLocalsRetainedByInitializer(Path, C->getFalseExpr(), Visit, true);
+ visitLocalsRetainedByInitializer(Path, C->getFalseExpr(), Visit, true,
+ EnableLifetimeWarnings);
break;
}
@@ -6980,18 +7288,33 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
case IndirectLocalPathEntry::AddressOf:
case IndirectLocalPathEntry::LValToRVal:
case IndirectLocalPathEntry::LifetimeBoundCall:
+ case IndirectLocalPathEntry::GslPointerInit:
// These exist primarily to mark the path as not permitting or
// supporting lifetime extension.
break;
- case IndirectLocalPathEntry::DefaultInit:
case IndirectLocalPathEntry::VarInit:
+ if (cast<VarDecl>(Path[I].D)->isImplicit())
+ return SourceRange();
+ LLVM_FALLTHROUGH;
+ case IndirectLocalPathEntry::DefaultInit:
return Path[I].E->getSourceRange();
}
}
return E->getSourceRange();
}
+static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) {
+ for (auto It = Path.rbegin(), End = Path.rend(); It != End; ++It) {
+ if (It->Kind == IndirectLocalPathEntry::VarInit)
+ continue;
+ if (It->Kind == IndirectLocalPathEntry::AddressOf)
+ continue;
+ return It->Kind == IndirectLocalPathEntry::GslPointerInit;
+ }
+ return false;
+}
+
void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
Expr *Init) {
LifetimeResult LR = getEntityLifetime(&Entity);
@@ -7008,12 +7331,36 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
SourceRange DiagRange = nextPathEntryRange(Path, 0, L);
SourceLocation DiagLoc = DiagRange.getBegin();
+ auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);
+
+ bool IsGslPtrInitWithGslTempOwner = false;
+ bool IsLocalGslOwner = false;
+ if (pathOnlyInitializesGslPointer(Path)) {
+ if (isa<DeclRefExpr>(L)) {
+ // We do not want to follow the references when returning a pointer originating
+ // from a local owner to avoid the following false positive:
+ // int &p = *localUniquePtr;
+ // someContainer.add(std::move(localUniquePtr));
+ // return p;
+ IsLocalGslOwner = isRecordWithAttr<OwnerAttr>(L->getType());
+ if (pathContainsInit(Path) || !IsLocalGslOwner)
+ return false;
+ } else {
+ IsGslPtrInitWithGslTempOwner = MTE && !MTE->getExtendingDecl() &&
+ isRecordWithAttr<OwnerAttr>(MTE->getType());
+ // Skipping a chain of initializing gsl::Pointer annotated objects.
+ // We are looking only for the final source to find out if it was
+ // a local or temporary owner or the address of a local variable/param.
+ if (!IsGslPtrInitWithGslTempOwner)
+ return true;
+ }
+ }
+
switch (LK) {
case LK_FullExpression:
llvm_unreachable("already handled this");
case LK_Extended: {
- auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);
if (!MTE) {
// The initialized entity has lifetime beyond the full-expression,
// and the local entity does too, so don't warn.
@@ -7023,6 +7370,11 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
return false;
}
+ if (IsGslPtrInitWithGslTempOwner && DiagLoc.isValid()) {
+ Diag(DiagLoc, diag::warn_dangling_lifetime_pointer) << DiagRange;
+ return false;
+ }
+
// Lifetime-extend the temporary.
if (Path.empty()) {
// Update the storage duration of the materialized temporary.
@@ -7064,6 +7416,14 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
// temporary, the program is ill-formed.
if (auto *ExtendingDecl =
ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {
+ if (IsGslPtrInitWithGslTempOwner) {
+ Diag(DiagLoc, diag::warn_dangling_lifetime_pointer_member)
+ << ExtendingDecl << DiagRange;
+ Diag(ExtendingDecl->getLocation(),
+ diag::note_ref_or_ptr_member_declared_here)
+ << true;
+ return false;
+ }
bool IsSubobjectMember = ExtendingEntity != &Entity;
Diag(DiagLoc, shouldLifetimeExtendThroughPath(Path)
? diag::err_dangling_member
@@ -7094,6 +7454,11 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
if (pathContainsInit(Path))
return false;
+ // Suppress false positives for code like the one below:
+ // Ctor(unique_ptr<T> up) : member(*up), member2(move(up)) {}
+ if (IsLocalGslOwner && pathOnlyInitializesGslPointer(Path))
+ return false;
+
auto *DRE = dyn_cast<DeclRefExpr>(L);
auto *VD = DRE ? dyn_cast<VarDecl>(DRE->getDecl()) : nullptr;
if (!VD) {
@@ -7104,7 +7469,7 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
if (auto *Member =
ExtendingEntity ? ExtendingEntity->getDecl() : nullptr) {
- bool IsPointer = Member->getType()->isAnyPointerType();
+ bool IsPointer = !Member->getType()->isReferenceType();
Diag(DiagLoc, IsPointer ? diag::warn_init_ptr_member_to_parameter_addr
: diag::warn_bind_ref_member_to_parameter)
<< Member << VD << isa<ParmVarDecl>(VD) << DiagRange;
@@ -7118,10 +7483,13 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
case LK_New:
if (isa<MaterializeTemporaryExpr>(L)) {
- Diag(DiagLoc, RK == RK_ReferenceBinding
- ? diag::warn_new_dangling_reference
- : diag::warn_new_dangling_initializer_list)
- << !Entity.getParent() << DiagRange;
+ if (IsGslPtrInitWithGslTempOwner)
+ Diag(DiagLoc, diag::warn_dangling_lifetime_pointer) << DiagRange;
+ else
+ Diag(DiagLoc, RK == RK_ReferenceBinding
+ ? diag::warn_new_dangling_reference
+ : diag::warn_new_dangling_initializer_list)
+ << !Entity.getParent() << DiagRange;
} else {
// We can't determine if the allocation outlives the local declaration.
return false;
@@ -7164,7 +7532,8 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
break;
case IndirectLocalPathEntry::LifetimeBoundCall:
- // FIXME: Consider adding a note for this.
+ case IndirectLocalPathEntry::GslPointerInit:
+ // FIXME: Consider adding a note for these.
break;
case IndirectLocalPathEntry::DefaultInit: {
@@ -7189,12 +7558,16 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
return false;
};
+ bool EnableLifetimeWarnings = !getDiagnostics().isIgnored(
+ diag::warn_dangling_lifetime_pointer, SourceLocation());
llvm::SmallVector<IndirectLocalPathEntry, 8> Path;
if (Init->isGLValue())
visitLocalsRetainedByReferenceBinding(Path, Init, RK_ReferenceBinding,
- TemporaryVisitor);
+ TemporaryVisitor,
+ EnableLifetimeWarnings);
else
- visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false);
+ visitLocalsRetainedByInitializer(Path, Init, TemporaryVisitor, false,
+ EnableLifetimeWarnings);
}
static void DiagnoseNarrowingInInitList(Sema &S,
@@ -7837,7 +8210,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
Ty = S.Context.getRValueReferenceType(Ty);
else if ((*ResultType)->isLValueReferenceType())
Ty = S.Context.getLValueReferenceType(Ty,
- (*ResultType)->getAs<LValueReferenceType>()->isSpelledAsLValue());
+ (*ResultType)->castAs<LValueReferenceType>()->isSpelledAsLValue());
*ResultType = Ty;
}
@@ -8043,6 +8416,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
*ResultType = S.Context.getConstantArrayType(
IncompleteDest->getElementType(),
ConstantSource->getSize(),
+ ConstantSource->getSizeExpr(),
ArrayType::Normal, 0);
}
}
@@ -8108,7 +8482,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
// argument passing.
assert(Step->Type->isSamplerT() &&
"Sampler initialization on non-sampler type.");
- Expr *Init = CurInit.get();
+ Expr *Init = CurInit.get()->IgnoreParens();
QualType SourceType = Init->getType();
// Case 1
if (Entity.isParameterKind()) {
@@ -8285,7 +8659,7 @@ static void diagnoseListInit(Sema &S, const InitializedEntity &Entity,
E.withConst(),
llvm::APInt(S.Context.getTypeSize(S.Context.getSizeType()),
InitList->getNumInits()),
- clang::ArrayType::Normal, 0);
+ nullptr, clang::ArrayType::Normal, 0);
InitializedEntity HiddenArray =
InitializedEntity::InitializeTemporary(ArrayType);
return diagnoseListInit(S, HiddenArray, InitList);
@@ -8295,7 +8669,7 @@ static void diagnoseListInit(Sema &S, const InitializedEntity &Entity,
// A list-initialization failure for a reference means that we tried to
// create a temporary of the inner type (per [dcl.init.list]p3.6) and the
// inner initialization failed.
- QualType T = DestType->getAs<ReferenceType>()->getPointeeType();
+ QualType T = DestType->castAs<ReferenceType>()->getPointeeType();
diagnoseListInit(S, InitializedEntity::InitializeTemporary(T), InitList);
SourceLocation Loc = InitList->getBeginLoc();
if (auto *D = Entity.getDecl())
@@ -8652,7 +9026,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< InheritedFrom;
RecordDecl *BaseDecl
- = Entity.getBaseSpecifier()->getType()->getAs<RecordType>()
+ = Entity.getBaseSpecifier()->getType()->castAs<RecordType>()
->getDecl();
S.Diag(BaseDecl->getLocation(), diag::note_previous_decl)
<< S.Context.getTagDeclType(BaseDecl);
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 986524e6d56b..c6b19a0b195c 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -272,12 +272,11 @@ static bool isInInlineFunction(const DeclContext *DC) {
return false;
}
-MangleNumberingContext *
-Sema::getCurrentMangleNumberContext(const DeclContext *DC,
- Decl *&ManglingContextDecl) {
+std::tuple<MangleNumberingContext *, Decl *>
+Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
// Compute the context for allocating mangling numbers in the current
// expression, if the ABI requires them.
- ManglingContextDecl = ExprEvalContexts.back().ManglingContextDecl;
+ Decl *ManglingContextDecl = ExprEvalContexts.back().ManglingContextDecl;
enum ContextKind {
Normal,
@@ -325,22 +324,18 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC,
if ((IsInNonspecializedTemplate &&
!(ManglingContextDecl && isa<ParmVarDecl>(ManglingContextDecl))) ||
isInInlineFunction(CurContext)) {
- ManglingContextDecl = nullptr;
while (auto *CD = dyn_cast<CapturedDecl>(DC))
DC = CD->getParent();
- return &Context.getManglingNumberContext(DC);
+ return std::make_tuple(&Context.getManglingNumberContext(DC), nullptr);
}
- ManglingContextDecl = nullptr;
- return nullptr;
+ return std::make_tuple(nullptr, nullptr);
}
case StaticDataMember:
// -- the initializers of nonspecialized static members of template classes
- if (!IsInNonspecializedTemplate) {
- ManglingContextDecl = nullptr;
- return nullptr;
- }
+ if (!IsInNonspecializedTemplate)
+ return std::make_tuple(nullptr, ManglingContextDecl);
// Fall through to get the current context.
LLVM_FALLTHROUGH;
@@ -352,29 +347,24 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC,
// -- the initializers of inline variables
case VariableTemplate:
// -- the initializers of templated variables
- return &ExprEvalContexts.back().getMangleNumberingContext(Context);
+ return std::make_tuple(
+ &Context.getManglingNumberContext(ASTContext::NeedExtraManglingDecl,
+ ManglingContextDecl),
+ ManglingContextDecl);
}
llvm_unreachable("unexpected context");
}
-MangleNumberingContext &
-Sema::ExpressionEvaluationContextRecord::getMangleNumberingContext(
- ASTContext &Ctx) {
- assert(ManglingContextDecl && "Need to have a context declaration");
- if (!MangleNumbering)
- MangleNumbering = Ctx.createMangleNumberingContext();
- return *MangleNumbering;
-}
-
-CXXMethodDecl *Sema::startLambdaDefinition(
- CXXRecordDecl *Class, SourceRange IntroducerRange,
- TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc,
- ArrayRef<ParmVarDecl *> Params, ConstexprSpecKind ConstexprKind,
- Optional<std::pair<unsigned, Decl *>> Mangling) {
+CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
+ SourceRange IntroducerRange,
+ TypeSourceInfo *MethodTypeInfo,
+ SourceLocation EndLoc,
+ ArrayRef<ParmVarDecl *> Params,
+ ConstexprSpecKind ConstexprKind) {
QualType MethodType = MethodTypeInfo->getType();
TemplateParameterList *TemplateParams =
- getGenericLambdaTemplateParameterList(getCurLambda(), *this);
+ getGenericLambdaTemplateParameterList(getCurLambda(), *this);
// If a lambda appears in a dependent context or is a generic lambda (has
// template parameters) and has an 'auto' return type, deduce it to a
// dependent type.
@@ -407,6 +397,8 @@ CXXMethodDecl *Sema::startLambdaDefinition(
MethodType, MethodTypeInfo, SC_None,
/*isInline=*/true, ConstexprKind, EndLoc);
Method->setAccess(AS_public);
+ if (!TemplateParams)
+ Class->addDecl(Method);
// Temporarily set the lexical declaration context to the current
// context, so that the Scope stack matches the lexical nesting.
@@ -418,9 +410,10 @@ CXXMethodDecl *Sema::startLambdaDefinition(
TemplateParams,
Method) : nullptr;
if (TemplateMethod) {
- TemplateMethod->setLexicalDeclContext(CurContext);
TemplateMethod->setAccess(AS_public);
Method->setDescribedFunctionTemplate(TemplateMethod);
+ Class->addDecl(TemplateMethod);
+ TemplateMethod->setLexicalDeclContext(CurContext);
}
// Add parameters.
@@ -433,19 +426,56 @@ CXXMethodDecl *Sema::startLambdaDefinition(
P->setOwningFunction(Method);
}
+ return Method;
+}
+
+void Sema::handleLambdaNumbering(
+ CXXRecordDecl *Class, CXXMethodDecl *Method,
+ Optional<std::tuple<unsigned, bool, Decl *>> Mangling) {
if (Mangling) {
- Class->setLambdaMangling(Mangling->first, Mangling->second);
- } else {
+ unsigned ManglingNumber;
+ bool HasKnownInternalLinkage;
Decl *ManglingContextDecl;
- if (MangleNumberingContext *MCtx =
- getCurrentMangleNumberContext(Class->getDeclContext(),
- ManglingContextDecl)) {
- unsigned ManglingNumber = MCtx->getManglingNumber(Method);
- Class->setLambdaMangling(ManglingNumber, ManglingContextDecl);
- }
+ std::tie(ManglingNumber, HasKnownInternalLinkage, ManglingContextDecl) =
+ Mangling.getValue();
+ Class->setLambdaMangling(ManglingNumber, ManglingContextDecl,
+ HasKnownInternalLinkage);
+ return;
}
- return Method;
+ auto getMangleNumberingContext =
+ [this](CXXRecordDecl *Class,
+ Decl *ManglingContextDecl) -> MangleNumberingContext * {
+ // Get mangle numbering context if there's any extra decl context.
+ if (ManglingContextDecl)
+ return &Context.getManglingNumberContext(
+ ASTContext::NeedExtraManglingDecl, ManglingContextDecl);
+ // Otherwise, from that lambda's decl context.
+ auto DC = Class->getDeclContext();
+ while (auto *CD = dyn_cast<CapturedDecl>(DC))
+ DC = CD->getParent();
+ return &Context.getManglingNumberContext(DC);
+ };
+
+ MangleNumberingContext *MCtx;
+ Decl *ManglingContextDecl;
+ std::tie(MCtx, ManglingContextDecl) =
+ getCurrentMangleNumberContext(Class->getDeclContext());
+ bool HasKnownInternalLinkage = false;
+ if (!MCtx && getLangOpts().CUDA) {
+ // Force lambda numbering in CUDA/HIP as we need to name lambdas following
+ // ODR. Both device- and host-compilation need to have a consistent naming
+ // on kernel functions. As lambdas are potential part of these `__global__`
+ // function names, they needs numbering following ODR.
+ MCtx = getMangleNumberingContext(Class, ManglingContextDecl);
+ assert(MCtx && "Retrieving mangle numbering context failed!");
+ HasKnownInternalLinkage = true;
+ }
+ if (MCtx) {
+ unsigned ManglingNumber = MCtx->getManglingNumber(Method);
+ Class->setLambdaMangling(ManglingNumber, ManglingContextDecl,
+ HasKnownInternalLinkage);
+ }
}
void Sema::buildLambdaScope(LambdaScopeInfo *LSI,
@@ -839,6 +869,8 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
NewVD->setInitStyle(static_cast<VarDecl::InitializationStyle>(InitStyle));
NewVD->markUsed(Context);
NewVD->setInit(Init);
+ if (NewVD->isParameterPack())
+ getCurLambda()->LocalPacks.push_back(NewVD);
return NewVD;
}
@@ -928,12 +960,12 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// Check for unexpanded parameter packs in the method type.
if (MethodTyInfo->getType()->containsUnexpandedParameterPack())
- ContainsUnexpandedParameterPack = true;
+ DiagnoseUnexpandedParameterPack(Intro.Range.getBegin(), MethodTyInfo,
+ UPPC_DeclarationType);
}
CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, MethodTyInfo,
KnownDependent, Intro.Default);
-
CXXMethodDecl *Method =
startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
ParamInfo.getDeclSpec().getConstexprSpecifier());
@@ -956,6 +988,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (getLangOpts().CUDA)
CUDASetLambdaAttrs(Method);
+ // Number the lambda for linkage purposes if necessary.
+ handleLambdaNumbering(Class, Method);
+
// Introduce the function call operator as the current declaration context.
PushDeclContext(CurScope, Method);
@@ -1053,7 +1088,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (C->Init.get()->containsUnexpandedParameterPack() &&
!C->InitCaptureType.get()->getAs<PackExpansionType>())
- ContainsUnexpandedParameterPack = true;
+ DiagnoseUnexpandedParameterPack(C->Init.get(), UPPC_Initializer);
unsigned InitStyle;
switch (C->InitKind) {
@@ -1184,7 +1219,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
}
finishLambdaExplicitCaptures(LSI);
- LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
+ LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;
// Add lambda parameters into scope.
addLambdaParameters(Intro.Captures, Method, CurScope);
@@ -1639,8 +1674,9 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
? CallOperator->getDescribedFunctionTemplate()
: cast<Decl>(CallOperator);
+ // FIXME: Is this really the best choice? Keeping the lexical decl context
+ // set as CurContext seems more faithful to the source.
TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class);
- Class->addDecl(TemplateOrNonTemplateCallOperatorDecl);
PopExpressionEvaluationContext();
@@ -1776,10 +1812,9 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
!CallOperator->isConstexpr() &&
!isa<CoroutineBodyStmt>(CallOperator->getBody()) &&
!Class->getDeclContext()->isDependentContext()) {
- TentativeAnalysisScope DiagnosticScopeGuard(*this);
CallOperator->setConstexprKind(
- (CheckConstexprFunctionDecl(CallOperator) &&
- CheckConstexprFunctionBody(CallOperator, CallOperator->getBody()))
+ CheckConstexprFunctionDefinition(CallOperator,
+ CheckConstexprKind::CheckValid)
? CSK_constexpr
: CSK_unspecified);
}
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 8a24dd884a76..d56c5980237c 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -673,82 +673,160 @@ LLVM_DUMP_METHOD void LookupResult::dump() {
D->dump();
}
-/// When trying to resolve a function name, if the isOpenCLBuiltin function
-/// defined in "OpenCLBuiltins.inc" returns a non-null <Index, Len>, then the
-/// identifier is referencing an OpenCL builtin function. Thus, all its
-/// prototypes are added to the LookUpResult.
+/// Get the QualType instances of the return type and arguments for an OpenCL
+/// builtin function signature.
+/// \param Context (in) The Context instance.
+/// \param OpenCLBuiltin (in) The signature currently handled.
+/// \param GenTypeMaxCnt (out) Maximum number of types contained in a generic
+/// type used as return type or as argument.
+/// Only meaningful for generic types, otherwise equals 1.
+/// \param RetTypes (out) List of the possible return types.
+/// \param ArgTypes (out) List of the possible argument types. For each
+/// argument, ArgTypes contains QualTypes for the Cartesian product
+/// of (vector sizes) x (types) .
+static void GetQualTypesForOpenCLBuiltin(
+ ASTContext &Context, const OpenCLBuiltinStruct &OpenCLBuiltin,
+ unsigned &GenTypeMaxCnt, SmallVector<QualType, 1> &RetTypes,
+ SmallVector<SmallVector<QualType, 1>, 5> &ArgTypes) {
+ // Get the QualType instances of the return types.
+ unsigned Sig = SignatureTable[OpenCLBuiltin.SigTableIndex];
+ OCL2Qual(Context, TypeTable[Sig], RetTypes);
+ GenTypeMaxCnt = RetTypes.size();
+
+ // Get the QualType instances of the arguments.
+ // First type is the return type, skip it.
+ for (unsigned Index = 1; Index < OpenCLBuiltin.NumTypes; Index++) {
+ SmallVector<QualType, 1> Ty;
+ OCL2Qual(Context,
+ TypeTable[SignatureTable[OpenCLBuiltin.SigTableIndex + Index]], Ty);
+ GenTypeMaxCnt = (Ty.size() > GenTypeMaxCnt) ? Ty.size() : GenTypeMaxCnt;
+ ArgTypes.push_back(std::move(Ty));
+ }
+}
+
+/// Create a list of the candidate function overloads for an OpenCL builtin
+/// function.
+/// \param Context (in) The ASTContext instance.
+/// \param GenTypeMaxCnt (in) Maximum number of types contained in a generic
+/// type used as return type or as argument.
+/// Only meaningful for generic types, otherwise equals 1.
+/// \param FunctionList (out) List of FunctionTypes.
+/// \param RetTypes (in) List of the possible return types.
+/// \param ArgTypes (in) List of the possible types for the arguments.
+static void GetOpenCLBuiltinFctOverloads(
+ ASTContext &Context, unsigned GenTypeMaxCnt,
+ std::vector<QualType> &FunctionList, SmallVector<QualType, 1> &RetTypes,
+ SmallVector<SmallVector<QualType, 1>, 5> &ArgTypes) {
+ FunctionProtoType::ExtProtoInfo PI;
+ PI.Variadic = false;
+
+ // Create FunctionTypes for each (gen)type.
+ for (unsigned IGenType = 0; IGenType < GenTypeMaxCnt; IGenType++) {
+ SmallVector<QualType, 5> ArgList;
+
+ for (unsigned A = 0; A < ArgTypes.size(); A++) {
+ // Builtins such as "max" have an "sgentype" argument that represents
+ // the corresponding scalar type of a gentype. The number of gentypes
+ // must be a multiple of the number of sgentypes.
+ assert(GenTypeMaxCnt % ArgTypes[A].size() == 0 &&
+ "argument type count not compatible with gentype type count");
+ unsigned Idx = IGenType % ArgTypes[A].size();
+ ArgList.push_back(ArgTypes[A][Idx]);
+ }
+
+ FunctionList.push_back(Context.getFunctionType(
+ RetTypes[(RetTypes.size() != 1) ? IGenType : 0], ArgList, PI));
+ }
+}
+
+/// When trying to resolve a function name, if isOpenCLBuiltin() returns a
+/// non-null <Index, Len> pair, then the name is referencing an OpenCL
+/// builtin function. Add all candidate signatures to the LookUpResult.
///
-/// \param S The Sema instance
-/// \param LR The LookupResult instance
-/// \param II The identifier being resolved
-/// \param Index The list of prototypes starts at Index in OpenCLBuiltins[]
-/// \param Len The list of prototypes has Len elements
-static void InsertOCLBuiltinDeclarations(Sema &S, LookupResult &LR,
- IdentifierInfo *II, unsigned Index,
- unsigned Len) {
-
- for (unsigned i = 0; i < Len; ++i) {
- const OpenCLBuiltinDecl &Decl = OpenCLBuiltins[Index - 1 + i];
+/// \param S (in) The Sema instance.
+/// \param LR (inout) The LookupResult instance.
+/// \param II (in) The identifier being resolved.
+/// \param FctIndex (in) Starting index in the BuiltinTable.
+/// \param Len (in) The signature list has Len elements.
+static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR,
+ IdentifierInfo *II,
+ const unsigned FctIndex,
+ const unsigned Len) {
+ // The builtin function declaration uses generic types (gentype).
+ bool HasGenType = false;
+
+ // Maximum number of types contained in a generic type used as return type or
+ // as argument. Only meaningful for generic types, otherwise equals 1.
+ unsigned GenTypeMaxCnt;
+
+ for (unsigned SignatureIndex = 0; SignatureIndex < Len; SignatureIndex++) {
+ const OpenCLBuiltinStruct &OpenCLBuiltin =
+ BuiltinTable[FctIndex + SignatureIndex];
ASTContext &Context = S.Context;
- // Ignore this BIF if the version is incorrect.
- if (Context.getLangOpts().OpenCLVersion < Decl.Version)
+ // Ignore this BIF if its version does not match the language options.
+ if (Context.getLangOpts().OpenCLVersion < OpenCLBuiltin.MinVersion)
+ continue;
+ if ((OpenCLBuiltin.MaxVersion != 0) &&
+ (Context.getLangOpts().OpenCLVersion >= OpenCLBuiltin.MaxVersion))
continue;
- FunctionProtoType::ExtProtoInfo PI;
- PI.Variadic = false;
-
- // Defined in "OpenCLBuiltins.inc"
- QualType RT = OCL2Qual(Context, OpenCLSignature[Decl.ArgTableIndex]);
+ SmallVector<QualType, 1> RetTypes;
+ SmallVector<SmallVector<QualType, 1>, 5> ArgTypes;
- SmallVector<QualType, 5> ArgTypes;
- for (unsigned I = 1; I < Decl.NumArgs; I++) {
- QualType Ty = OCL2Qual(Context, OpenCLSignature[Decl.ArgTableIndex + I]);
- ArgTypes.push_back(Ty);
+ // Obtain QualType lists for the function signature.
+ GetQualTypesForOpenCLBuiltin(Context, OpenCLBuiltin, GenTypeMaxCnt,
+ RetTypes, ArgTypes);
+ if (GenTypeMaxCnt > 1) {
+ HasGenType = true;
}
- QualType R = Context.getFunctionType(RT, ArgTypes, PI);
- SourceLocation Loc = LR.getNameLoc();
+ // Create function overload for each type combination.
+ std::vector<QualType> FunctionList;
+ GetOpenCLBuiltinFctOverloads(Context, GenTypeMaxCnt, FunctionList, RetTypes,
+ ArgTypes);
- // TODO: This part is taken from Sema::LazilyCreateBuiltin,
- // maybe refactor it.
+ SourceLocation Loc = LR.getNameLoc();
DeclContext *Parent = Context.getTranslationUnitDecl();
- FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, R,
- /*TInfo=*/nullptr, SC_Extern,
- false, R->isFunctionProtoType());
- New->setImplicit();
-
- // Create Decl objects for each parameter, adding them to the
- // FunctionDecl.
- if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) {
- SmallVector<ParmVarDecl *, 16> Params;
- for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {
- ParmVarDecl *Parm =
- ParmVarDecl::Create(Context, New, SourceLocation(),
- SourceLocation(), nullptr, FT->getParamType(i),
- /*TInfo=*/nullptr, SC_None, nullptr);
- Parm->setScopeInfo(0, i);
- Params.push_back(Parm);
+ FunctionDecl *NewOpenCLBuiltin;
+
+ for (unsigned Index = 0; Index < GenTypeMaxCnt; Index++) {
+ NewOpenCLBuiltin = FunctionDecl::Create(
+ Context, Parent, Loc, Loc, II, FunctionList[Index],
+ /*TInfo=*/nullptr, SC_Extern, false,
+ FunctionList[Index]->isFunctionProtoType());
+ NewOpenCLBuiltin->setImplicit();
+
+ // Create Decl objects for each parameter, adding them to the
+ // FunctionDecl.
+ if (const FunctionProtoType *FP =
+ dyn_cast<FunctionProtoType>(FunctionList[Index])) {
+ SmallVector<ParmVarDecl *, 16> ParmList;
+ for (unsigned IParm = 0, e = FP->getNumParams(); IParm != e; ++IParm) {
+ ParmVarDecl *Parm = ParmVarDecl::Create(
+ Context, NewOpenCLBuiltin, SourceLocation(), SourceLocation(),
+ nullptr, FP->getParamType(IParm),
+ /*TInfo=*/nullptr, SC_None, nullptr);
+ Parm->setScopeInfo(0, IParm);
+ ParmList.push_back(Parm);
+ }
+ NewOpenCLBuiltin->setParams(ParmList);
}
- New->setParams(Params);
+ if (!S.getLangOpts().OpenCLCPlusPlus) {
+ NewOpenCLBuiltin->addAttr(OverloadableAttr::CreateImplicit(Context));
+ }
+ LR.addDecl(NewOpenCLBuiltin);
}
-
- New->addAttr(OverloadableAttr::CreateImplicit(Context));
-
- if (strlen(Decl.Extension))
- S.setOpenCLExtensionForDecl(New, Decl.Extension);
-
- LR.addDecl(New);
}
// If we added overloads, need to resolve the lookup result.
- if (Len > 1)
+ if (Len > 1 || HasGenType)
LR.resolveKind();
}
/// Lookup a builtin function, when name lookup would otherwise
/// fail.
-static bool LookupBuiltin(Sema &S, LookupResult &R) {
+bool Sema::LookupBuiltin(LookupResult &R) {
Sema::LookupNameKind NameKind = R.getLookupKind();
// If we didn't find a use of this identifier, and if the identifier
@@ -758,21 +836,22 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
NameKind == Sema::LookupRedeclarationWithLinkage) {
IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo();
if (II) {
- if (S.getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) {
- if (II == S.getASTContext().getMakeIntegerSeqName()) {
- R.addDecl(S.getASTContext().getMakeIntegerSeqDecl());
+ if (getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) {
+ if (II == getASTContext().getMakeIntegerSeqName()) {
+ R.addDecl(getASTContext().getMakeIntegerSeqDecl());
return true;
- } else if (II == S.getASTContext().getTypePackElementName()) {
- R.addDecl(S.getASTContext().getTypePackElementDecl());
+ } else if (II == getASTContext().getTypePackElementName()) {
+ R.addDecl(getASTContext().getTypePackElementDecl());
return true;
}
}
// Check if this is an OpenCL Builtin, and if so, insert its overloads.
- if (S.getLangOpts().OpenCL && S.getLangOpts().DeclareOpenCLBuiltins) {
+ if (getLangOpts().OpenCL && getLangOpts().DeclareOpenCLBuiltins) {
auto Index = isOpenCLBuiltin(II->getName());
if (Index.first) {
- InsertOCLBuiltinDeclarations(S, R, II, Index.first, Index.second);
+ InsertOCLBuiltinDeclarationsFromTable(*this, R, II, Index.first - 1,
+ Index.second);
return true;
}
}
@@ -781,14 +860,14 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
if (unsigned BuiltinID = II->getBuiltinID()) {
// In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined
// library functions like 'malloc'. Instead, we'll just error.
- if ((S.getLangOpts().CPlusPlus || S.getLangOpts().OpenCL) &&
- S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
+ if ((getLangOpts().CPlusPlus || getLangOpts().OpenCL) &&
+ Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return false;
- if (NamedDecl *D = S.LazilyCreateBuiltin((IdentifierInfo *)II,
- BuiltinID, S.TUScope,
- R.isForRedeclaration(),
- R.getNameLoc())) {
+ if (NamedDecl *D = LazilyCreateBuiltin((IdentifierInfo *)II,
+ BuiltinID, TUScope,
+ R.isForRedeclaration(),
+ R.getNameLoc())) {
R.addDecl(D);
return true;
}
@@ -934,7 +1013,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
}
}
- if (!Found && DC->isTranslationUnit() && LookupBuiltin(S, R))
+ if (!Found && DC->isTranslationUnit() && S.LookupBuiltin(R))
return true;
if (R.getLookupName().getNameKind()
@@ -1932,7 +2011,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) {
// If we didn't find a use of this identifier, and if the identifier
// corresponds to a compiler builtin, create the decl object for the builtin
// now, injecting it into translation unit scope, and return it.
- if (AllowBuiltinCreation && LookupBuiltin(*this, R))
+ if (AllowBuiltinCreation && LookupBuiltin(R))
return true;
// If we didn't find a use of this identifier, the ExternalSource
@@ -2051,7 +2130,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
/// Callback that looks for any member of a class with the given name.
static bool LookupAnyMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, DeclarationName Name) {
- RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
+ RecordDecl *BaseRecord = Specifier->getType()->castAs<RecordType>()->getDecl();
Path.Decls = BaseRecord->lookup(Name);
return !Path.Decls.empty();
@@ -2750,7 +2829,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class:
#define ABSTRACT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
// T is canonical. We can also ignore dependent types because
// we don't need to do ADL at the definition point, but if we
// wanted to implement template export (or if we find some other
@@ -3016,8 +3095,11 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
SpecialMemberCache.InsertNode(Result, InsertPoint);
if (SM == CXXDestructor) {
- if (RD->needsImplicitDestructor())
- DeclareImplicitDestructor(RD);
+ if (RD->needsImplicitDestructor()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitDestructor(RD);
+ });
+ }
CXXDestructorDecl *DD = RD->getDestructor();
assert(DD && "record without a destructor");
Result->setMethod(DD);
@@ -3040,21 +3122,36 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
if (SM == CXXDefaultConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
NumArgs = 0;
- if (RD->needsImplicitDefaultConstructor())
- DeclareImplicitDefaultConstructor(RD);
+ if (RD->needsImplicitDefaultConstructor()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitDefaultConstructor(RD);
+ });
+ }
} else {
if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
- if (RD->needsImplicitCopyConstructor())
- DeclareImplicitCopyConstructor(RD);
- if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor())
- DeclareImplicitMoveConstructor(RD);
+ if (RD->needsImplicitCopyConstructor()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitCopyConstructor(RD);
+ });
+ }
+ if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitMoveConstructor(RD);
+ });
+ }
} else {
Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
- if (RD->needsImplicitCopyAssignment())
- DeclareImplicitCopyAssignment(RD);
- if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment())
- DeclareImplicitMoveAssignment(RD);
+ if (RD->needsImplicitCopyAssignment()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitCopyAssignment(RD);
+ });
+ }
+ if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment()) {
+ runWithSufficientStackSpace(RD->getLocation(), [&] {
+ DeclareImplicitMoveAssignment(RD);
+ });
+ }
}
if (ConstArg)
@@ -3211,12 +3308,14 @@ CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class,
DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
// If the implicit constructors have not yet been declared, do so now.
if (CanDeclareSpecialMemberFunction(Class)) {
- if (Class->needsImplicitDefaultConstructor())
- DeclareImplicitDefaultConstructor(Class);
- if (Class->needsImplicitCopyConstructor())
- DeclareImplicitCopyConstructor(Class);
- if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor())
- DeclareImplicitMoveConstructor(Class);
+ runWithSufficientStackSpace(Class->getLocation(), [&] {
+ if (Class->needsImplicitDefaultConstructor())
+ DeclareImplicitDefaultConstructor(Class);
+ if (Class->needsImplicitCopyConstructor())
+ DeclareImplicitCopyConstructor(Class);
+ if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor())
+ DeclareImplicitMoveConstructor(Class);
+ });
}
CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class));
@@ -3609,328 +3708,347 @@ NamedDecl *VisibleDeclsRecord::checkHidden(NamedDecl *ND) {
return nullptr;
}
-static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
- bool QualifiedNameLookup,
- bool InBaseClass,
- VisibleDeclConsumer &Consumer,
- VisibleDeclsRecord &Visited,
- bool IncludeDependentBases,
- bool LoadExternal) {
- if (!Ctx)
- return;
-
- // Make sure we don't visit the same context twice.
- if (Visited.visitedContext(Ctx->getPrimaryContext()))
- return;
-
- Consumer.EnteredContext(Ctx);
-
- // Outside C++, lookup results for the TU live on identifiers.
- if (isa<TranslationUnitDecl>(Ctx) &&
- !Result.getSema().getLangOpts().CPlusPlus) {
- auto &S = Result.getSema();
- auto &Idents = S.Context.Idents;
-
- // Ensure all external identifiers are in the identifier table.
- if (LoadExternal)
- if (IdentifierInfoLookup *External = Idents.getExternalIdentifierLookup()) {
- std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers());
- for (StringRef Name = Iter->Next(); !Name.empty(); Name = Iter->Next())
- Idents.get(Name);
- }
+namespace {
+class LookupVisibleHelper {
+public:
+ LookupVisibleHelper(VisibleDeclConsumer &Consumer, bool IncludeDependentBases,
+ bool LoadExternal)
+ : Consumer(Consumer), IncludeDependentBases(IncludeDependentBases),
+ LoadExternal(LoadExternal) {}
+
+ void lookupVisibleDecls(Sema &SemaRef, Scope *S, Sema::LookupNameKind Kind,
+ bool IncludeGlobalScope) {
+ // Determine the set of using directives available during
+ // unqualified name lookup.
+ Scope *Initial = S;
+ UnqualUsingDirectiveSet UDirs(SemaRef);
+ if (SemaRef.getLangOpts().CPlusPlus) {
+ // Find the first namespace or translation-unit scope.
+ while (S && !isNamespaceOrTranslationUnitScope(S))
+ S = S->getParent();
- // Walk all lookup results in the TU for each identifier.
- for (const auto &Ident : Idents) {
- for (auto I = S.IdResolver.begin(Ident.getValue()),
- E = S.IdResolver.end();
- I != E; ++I) {
- if (S.IdResolver.isDeclInScope(*I, Ctx)) {
- if (NamedDecl *ND = Result.getAcceptableDecl(*I)) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
- Visited.add(ND);
- }
- }
- }
+ UDirs.visitScopeChain(Initial, S);
}
+ UDirs.done();
- return;
+ // Look for visible declarations.
+ LookupResult Result(SemaRef, DeclarationName(), SourceLocation(), Kind);
+ Result.setAllowHidden(Consumer.includeHiddenDecls());
+ if (!IncludeGlobalScope)
+ Visited.visitedContext(SemaRef.getASTContext().getTranslationUnitDecl());
+ ShadowContextRAII Shadow(Visited);
+ lookupInScope(Initial, Result, UDirs);
}
- if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx))
- Result.getSema().ForceDeclarationOfImplicitMembers(Class);
+ void lookupVisibleDecls(Sema &SemaRef, DeclContext *Ctx,
+ Sema::LookupNameKind Kind, bool IncludeGlobalScope) {
+ LookupResult Result(SemaRef, DeclarationName(), SourceLocation(), Kind);
+ Result.setAllowHidden(Consumer.includeHiddenDecls());
+ if (!IncludeGlobalScope)
+ Visited.visitedContext(SemaRef.getASTContext().getTranslationUnitDecl());
- // We sometimes skip loading namespace-level results (they tend to be huge).
- bool Load = LoadExternal ||
- !(isa<TranslationUnitDecl>(Ctx) || isa<NamespaceDecl>(Ctx));
- // Enumerate all of the results in this context.
- for (DeclContextLookupResult R :
- Load ? Ctx->lookups()
- : Ctx->noload_lookups(/*PreserveInternalState=*/false)) {
- for (auto *D : R) {
- if (auto *ND = Result.getAcceptableDecl(D)) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
- Visited.add(ND);
- }
- }
- }
-
- // Traverse using directives for qualified name lookup.
- if (QualifiedNameLookup) {
ShadowContextRAII Shadow(Visited);
- for (auto I : Ctx->using_directives()) {
- if (!Result.getSema().isVisible(I))
- continue;
- LookupVisibleDecls(I->getNominatedNamespace(), Result,
- QualifiedNameLookup, InBaseClass, Consumer, Visited,
- IncludeDependentBases, LoadExternal);
- }
+ lookupInDeclContext(Ctx, Result, /*QualifiedNameLookup=*/true,
+ /*InBaseClass=*/false);
}
- // Traverse the contexts of inherited C++ classes.
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
- if (!Record->hasDefinition())
+private:
+ void lookupInDeclContext(DeclContext *Ctx, LookupResult &Result,
+ bool QualifiedNameLookup, bool InBaseClass) {
+ if (!Ctx)
return;
- for (const auto &B : Record->bases()) {
- QualType BaseType = B.getType();
+ // Make sure we don't visit the same context twice.
+ if (Visited.visitedContext(Ctx->getPrimaryContext()))
+ return;
- RecordDecl *RD;
- if (BaseType->isDependentType()) {
- if (!IncludeDependentBases) {
- // Don't look into dependent bases, because name lookup can't look
- // there anyway.
- continue;
+ Consumer.EnteredContext(Ctx);
+
+ // Outside C++, lookup results for the TU live on identifiers.
+ if (isa<TranslationUnitDecl>(Ctx) &&
+ !Result.getSema().getLangOpts().CPlusPlus) {
+ auto &S = Result.getSema();
+ auto &Idents = S.Context.Idents;
+
+ // Ensure all external identifiers are in the identifier table.
+ if (LoadExternal)
+ if (IdentifierInfoLookup *External =
+ Idents.getExternalIdentifierLookup()) {
+ std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers());
+ for (StringRef Name = Iter->Next(); !Name.empty();
+ Name = Iter->Next())
+ Idents.get(Name);
+ }
+
+ // Walk all lookup results in the TU for each identifier.
+ for (const auto &Ident : Idents) {
+ for (auto I = S.IdResolver.begin(Ident.getValue()),
+ E = S.IdResolver.end();
+ I != E; ++I) {
+ if (S.IdResolver.isDeclInScope(*I, Ctx)) {
+ if (NamedDecl *ND = Result.getAcceptableDecl(*I)) {
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
+ Visited.add(ND);
+ }
+ }
}
- const auto *TST = BaseType->getAs<TemplateSpecializationType>();
- if (!TST)
- continue;
- TemplateName TN = TST->getTemplateName();
- const auto *TD =
- dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
- if (!TD)
- continue;
- RD = TD->getTemplatedDecl();
- } else {
- const auto *Record = BaseType->getAs<RecordType>();
- if (!Record)
- continue;
- RD = Record->getDecl();
}
- // FIXME: It would be nice to be able to determine whether referencing
- // a particular member would be ambiguous. For example, given
- //
- // struct A { int member; };
- // struct B { int member; };
- // struct C : A, B { };
- //
- // void f(C *c) { c->### }
- //
- // accessing 'member' would result in an ambiguity. However, we
- // could be smart enough to qualify the member with the base
- // class, e.g.,
- //
- // c->B::member
- //
- // or
- //
- // c->A::member
-
- // Find results in this base class (and its bases).
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(RD, Result, QualifiedNameLookup, /*InBaseClass=*/true,
- Consumer, Visited, IncludeDependentBases,
- LoadExternal);
+ return;
}
- }
- // Traverse the contexts of Objective-C classes.
- if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) {
- // Traverse categories.
- for (auto *Cat : IFace->visible_categories()) {
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(Cat, Result, QualifiedNameLookup, false, Consumer,
- Visited, IncludeDependentBases, LoadExternal);
+ if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx))
+ Result.getSema().ForceDeclarationOfImplicitMembers(Class);
+
+ // We sometimes skip loading namespace-level results (they tend to be huge).
+ bool Load = LoadExternal ||
+ !(isa<TranslationUnitDecl>(Ctx) || isa<NamespaceDecl>(Ctx));
+ // Enumerate all of the results in this context.
+ for (DeclContextLookupResult R :
+ Load ? Ctx->lookups()
+ : Ctx->noload_lookups(/*PreserveInternalState=*/false)) {
+ for (auto *D : R) {
+ if (auto *ND = Result.getAcceptableDecl(D)) {
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
+ Visited.add(ND);
+ }
+ }
}
- // Traverse protocols.
- for (auto *I : IFace->all_referenced_protocols()) {
+ // Traverse using directives for qualified name lookup.
+ if (QualifiedNameLookup) {
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer,
- Visited, IncludeDependentBases, LoadExternal);
+ for (auto I : Ctx->using_directives()) {
+ if (!Result.getSema().isVisible(I))
+ continue;
+ lookupInDeclContext(I->getNominatedNamespace(), Result,
+ QualifiedNameLookup, InBaseClass);
+ }
}
- // Traverse the superclass.
- if (IFace->getSuperClass()) {
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(IFace->getSuperClass(), Result, QualifiedNameLookup,
- true, Consumer, Visited, IncludeDependentBases,
- LoadExternal);
- }
+ // Traverse the contexts of inherited C++ classes.
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
+ if (!Record->hasDefinition())
+ return;
- // If there is an implementation, traverse it. We do this to find
- // synthesized ivars.
- if (IFace->getImplementation()) {
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(IFace->getImplementation(), Result,
- QualifiedNameLookup, InBaseClass, Consumer, Visited,
- IncludeDependentBases, LoadExternal);
- }
- } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) {
- for (auto *I : Protocol->protocols()) {
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer,
- Visited, IncludeDependentBases, LoadExternal);
- }
- } else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) {
- for (auto *I : Category->protocols()) {
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(I, Result, QualifiedNameLookup, false, Consumer,
- Visited, IncludeDependentBases, LoadExternal);
+ for (const auto &B : Record->bases()) {
+ QualType BaseType = B.getType();
+
+ RecordDecl *RD;
+ if (BaseType->isDependentType()) {
+ if (!IncludeDependentBases) {
+ // Don't look into dependent bases, because name lookup can't look
+ // there anyway.
+ continue;
+ }
+ const auto *TST = BaseType->getAs<TemplateSpecializationType>();
+ if (!TST)
+ continue;
+ TemplateName TN = TST->getTemplateName();
+ const auto *TD =
+ dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
+ if (!TD)
+ continue;
+ RD = TD->getTemplatedDecl();
+ } else {
+ const auto *Record = BaseType->getAs<RecordType>();
+ if (!Record)
+ continue;
+ RD = Record->getDecl();
+ }
+
+ // FIXME: It would be nice to be able to determine whether referencing
+ // a particular member would be ambiguous. For example, given
+ //
+ // struct A { int member; };
+ // struct B { int member; };
+ // struct C : A, B { };
+ //
+ // void f(C *c) { c->### }
+ //
+ // accessing 'member' would result in an ambiguity. However, we
+ // could be smart enough to qualify the member with the base
+ // class, e.g.,
+ //
+ // c->B::member
+ //
+ // or
+ //
+ // c->A::member
+
+ // Find results in this base class (and its bases).
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(RD, Result, QualifiedNameLookup,
+ /*InBaseClass=*/true);
+ }
}
- // If there is an implementation, traverse it.
- if (Category->getImplementation()) {
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(Category->getImplementation(), Result,
- QualifiedNameLookup, true, Consumer, Visited,
- IncludeDependentBases, LoadExternal);
+ // Traverse the contexts of Objective-C classes.
+ if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) {
+ // Traverse categories.
+ for (auto *Cat : IFace->visible_categories()) {
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(Cat, Result, QualifiedNameLookup,
+ /*InBaseClass=*/false);
+ }
+
+ // Traverse protocols.
+ for (auto *I : IFace->all_referenced_protocols()) {
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(I, Result, QualifiedNameLookup,
+ /*InBaseClass=*/false);
+ }
+
+ // Traverse the superclass.
+ if (IFace->getSuperClass()) {
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(IFace->getSuperClass(), Result, QualifiedNameLookup,
+ /*InBaseClass=*/true);
+ }
+
+ // If there is an implementation, traverse it. We do this to find
+ // synthesized ivars.
+ if (IFace->getImplementation()) {
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(IFace->getImplementation(), Result,
+ QualifiedNameLookup, InBaseClass);
+ }
+ } else if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Ctx)) {
+ for (auto *I : Protocol->protocols()) {
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(I, Result, QualifiedNameLookup,
+ /*InBaseClass=*/false);
+ }
+ } else if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Ctx)) {
+ for (auto *I : Category->protocols()) {
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(I, Result, QualifiedNameLookup,
+ /*InBaseClass=*/false);
+ }
+
+ // If there is an implementation, traverse it.
+ if (Category->getImplementation()) {
+ ShadowContextRAII Shadow(Visited);
+ lookupInDeclContext(Category->getImplementation(), Result,
+ QualifiedNameLookup, /*InBaseClass=*/true);
+ }
}
}
-}
-static void LookupVisibleDecls(Scope *S, LookupResult &Result,
- UnqualUsingDirectiveSet &UDirs,
- VisibleDeclConsumer &Consumer,
- VisibleDeclsRecord &Visited,
- bool LoadExternal) {
- if (!S)
- return;
+ void lookupInScope(Scope *S, LookupResult &Result,
+ UnqualUsingDirectiveSet &UDirs) {
+ // No clients run in this mode and it's not supported. Please add tests and
+ // remove the assertion if you start relying on it.
+ assert(!IncludeDependentBases && "Unsupported flag for lookupInScope");
- if (!S->getEntity() ||
- (!S->getParent() &&
- !Visited.alreadyVisitedContext(S->getEntity())) ||
- (S->getEntity())->isFunctionOrMethod()) {
- FindLocalExternScope FindLocals(Result);
- // Walk through the declarations in this Scope. The consumer might add new
- // decls to the scope as part of deserialization, so make a copy first.
- SmallVector<Decl *, 8> ScopeDecls(S->decls().begin(), S->decls().end());
- for (Decl *D : ScopeDecls) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
- if ((ND = Result.getAcceptableDecl(ND))) {
- Consumer.FoundDecl(ND, Visited.checkHidden(ND), nullptr, false);
- Visited.add(ND);
- }
+ if (!S)
+ return;
+
+ if (!S->getEntity() ||
+ (!S->getParent() && !Visited.alreadyVisitedContext(S->getEntity())) ||
+ (S->getEntity())->isFunctionOrMethod()) {
+ FindLocalExternScope FindLocals(Result);
+ // Walk through the declarations in this Scope. The consumer might add new
+ // decls to the scope as part of deserialization, so make a copy first.
+ SmallVector<Decl *, 8> ScopeDecls(S->decls().begin(), S->decls().end());
+ for (Decl *D : ScopeDecls) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ if ((ND = Result.getAcceptableDecl(ND))) {
+ Consumer.FoundDecl(ND, Visited.checkHidden(ND), nullptr, false);
+ Visited.add(ND);
+ }
+ }
}
- }
- // FIXME: C++ [temp.local]p8
- DeclContext *Entity = nullptr;
- if (S->getEntity()) {
- // Look into this scope's declaration context, along with any of its
- // parent lookup contexts (e.g., enclosing classes), up to the point
- // where we hit the context stored in the next outer scope.
- Entity = S->getEntity();
- DeclContext *OuterCtx = findOuterContext(S).first; // FIXME
-
- for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx);
- Ctx = Ctx->getLookupParent()) {
- if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) {
- if (Method->isInstanceMethod()) {
- // For instance methods, look for ivars in the method's interface.
- LookupResult IvarResult(Result.getSema(), Result.getLookupName(),
- Result.getNameLoc(), Sema::LookupMemberName);
- if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) {
- LookupVisibleDecls(IFace, IvarResult, /*QualifiedNameLookup=*/false,
- /*InBaseClass=*/false, Consumer, Visited,
- /*IncludeDependentBases=*/false, LoadExternal);
+ // FIXME: C++ [temp.local]p8
+ DeclContext *Entity = nullptr;
+ if (S->getEntity()) {
+ // Look into this scope's declaration context, along with any of its
+ // parent lookup contexts (e.g., enclosing classes), up to the point
+ // where we hit the context stored in the next outer scope.
+ Entity = S->getEntity();
+ DeclContext *OuterCtx = findOuterContext(S).first; // FIXME
+
+ for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx);
+ Ctx = Ctx->getLookupParent()) {
+ if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(Ctx)) {
+ if (Method->isInstanceMethod()) {
+ // For instance methods, look for ivars in the method's interface.
+ LookupResult IvarResult(Result.getSema(), Result.getLookupName(),
+ Result.getNameLoc(),
+ Sema::LookupMemberName);
+ if (ObjCInterfaceDecl *IFace = Method->getClassInterface()) {
+ lookupInDeclContext(IFace, IvarResult,
+ /*QualifiedNameLookup=*/false,
+ /*InBaseClass=*/false);
+ }
}
+
+ // We've already performed all of the name lookup that we need
+ // to for Objective-C methods; the next context will be the
+ // outer scope.
+ break;
}
- // We've already performed all of the name lookup that we need
- // to for Objective-C methods; the next context will be the
- // outer scope.
- break;
- }
+ if (Ctx->isFunctionOrMethod())
+ continue;
- if (Ctx->isFunctionOrMethod())
- continue;
+ lookupInDeclContext(Ctx, Result, /*QualifiedNameLookup=*/false,
+ /*InBaseClass=*/false);
+ }
+ } else if (!S->getParent()) {
+ // Look into the translation unit scope. We walk through the translation
+ // unit's declaration context, because the Scope itself won't have all of
+ // the declarations if we loaded a precompiled header.
+ // FIXME: We would like the translation unit's Scope object to point to
+ // the translation unit, so we don't need this special "if" branch.
+ // However, doing so would force the normal C++ name-lookup code to look
+ // into the translation unit decl when the IdentifierInfo chains would
+ // suffice. Once we fix that problem (which is part of a more general
+ // "don't look in DeclContexts unless we have to" optimization), we can
+ // eliminate this.
+ Entity = Result.getSema().Context.getTranslationUnitDecl();
+ lookupInDeclContext(Entity, Result, /*QualifiedNameLookup=*/false,
+ /*InBaseClass=*/false);
+ }
- LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/false,
- /*InBaseClass=*/false, Consumer, Visited,
- /*IncludeDependentBases=*/false, LoadExternal);
+ if (Entity) {
+ // Lookup visible declarations in any namespaces found by using
+ // directives.
+ for (const UnqualUsingEntry &UUE : UDirs.getNamespacesFor(Entity))
+ lookupInDeclContext(
+ const_cast<DeclContext *>(UUE.getNominatedNamespace()), Result,
+ /*QualifiedNameLookup=*/false,
+ /*InBaseClass=*/false);
}
- } else if (!S->getParent()) {
- // Look into the translation unit scope. We walk through the translation
- // unit's declaration context, because the Scope itself won't have all of
- // the declarations if we loaded a precompiled header.
- // FIXME: We would like the translation unit's Scope object to point to the
- // translation unit, so we don't need this special "if" branch. However,
- // doing so would force the normal C++ name-lookup code to look into the
- // translation unit decl when the IdentifierInfo chains would suffice.
- // Once we fix that problem (which is part of a more general "don't look
- // in DeclContexts unless we have to" optimization), we can eliminate this.
- Entity = Result.getSema().Context.getTranslationUnitDecl();
- LookupVisibleDecls(Entity, Result, /*QualifiedNameLookup=*/false,
- /*InBaseClass=*/false, Consumer, Visited,
- /*IncludeDependentBases=*/false, LoadExternal);
- }
- if (Entity) {
- // Lookup visible declarations in any namespaces found by using
- // directives.
- for (const UnqualUsingEntry &UUE : UDirs.getNamespacesFor(Entity))
- LookupVisibleDecls(const_cast<DeclContext *>(UUE.getNominatedNamespace()),
- Result, /*QualifiedNameLookup=*/false,
- /*InBaseClass=*/false, Consumer, Visited,
- /*IncludeDependentBases=*/false, LoadExternal);
+ // Lookup names in the parent scope.
+ ShadowContextRAII Shadow(Visited);
+ lookupInScope(S->getParent(), Result, UDirs);
}
- // Lookup names in the parent scope.
- ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(S->getParent(), Result, UDirs, Consumer, Visited,
- LoadExternal);
-}
+private:
+ VisibleDeclsRecord Visited;
+ VisibleDeclConsumer &Consumer;
+ bool IncludeDependentBases;
+ bool LoadExternal;
+};
+} // namespace
void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind,
VisibleDeclConsumer &Consumer,
bool IncludeGlobalScope, bool LoadExternal) {
- // Determine the set of using directives available during
- // unqualified name lookup.
- Scope *Initial = S;
- UnqualUsingDirectiveSet UDirs(*this);
- if (getLangOpts().CPlusPlus) {
- // Find the first namespace or translation-unit scope.
- while (S && !isNamespaceOrTranslationUnitScope(S))
- S = S->getParent();
-
- UDirs.visitScopeChain(Initial, S);
- }
- UDirs.done();
-
- // Look for visible declarations.
- LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind);
- Result.setAllowHidden(Consumer.includeHiddenDecls());
- VisibleDeclsRecord Visited;
- if (!IncludeGlobalScope)
- Visited.visitedContext(Context.getTranslationUnitDecl());
- ShadowContextRAII Shadow(Visited);
- ::LookupVisibleDecls(Initial, Result, UDirs, Consumer, Visited, LoadExternal);
+ LookupVisibleHelper H(Consumer, /*IncludeDependentBases=*/false,
+ LoadExternal);
+ H.lookupVisibleDecls(*this, S, Kind, IncludeGlobalScope);
}
void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind,
VisibleDeclConsumer &Consumer,
bool IncludeGlobalScope,
bool IncludeDependentBases, bool LoadExternal) {
- LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind);
- Result.setAllowHidden(Consumer.includeHiddenDecls());
- VisibleDeclsRecord Visited;
- if (!IncludeGlobalScope)
- Visited.visitedContext(Context.getTranslationUnitDecl());
- ShadowContextRAII Shadow(Visited);
- ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true,
- /*InBaseClass=*/false, Consumer, Visited,
- IncludeDependentBases, LoadExternal);
+ LookupVisibleHelper H(Consumer, IncludeDependentBases, LoadExternal);
+ H.lookupVisibleDecls(*this, Ctx, Kind, IncludeGlobalScope);
}
/// LookupOrCreateLabel - Do a name lookup of a label with the specified name.
@@ -4745,7 +4863,7 @@ std::unique_ptr<TypoCorrectionConsumer> Sema::makeTypoCorrectionConsumer(
// occurs). Note that CorrectionCandidateCallback is polymorphic and
// initially stack-allocated.
std::unique_ptr<CorrectionCandidateCallback> ClonedCCC = CCC.clone();
- auto Consumer = llvm::make_unique<TypoCorrectionConsumer>(
+ auto Consumer = std::make_unique<TypoCorrectionConsumer>(
*this, TypoName, LookupKind, S, SS, std::move(ClonedCCC), MemberContext,
EnteringContext);
@@ -5164,8 +5282,11 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) {
return FD->getDefinition();
if (TagDecl *TD = dyn_cast<TagDecl>(D))
return TD->getDefinition();
+ // The first definition for this ObjCInterfaceDecl might be in the TU
+ // and not associated with any module. Use the one we know to be complete
+ // and have just seen in a module.
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
- return ID->getDefinition();
+ return ID;
if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
return PD->getDefinition();
if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
@@ -5361,6 +5482,8 @@ TypoExpr *Sema::createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC,
State.Consumer = std::move(TCC);
State.DiagHandler = std::move(TDG);
State.RecoveryHandler = std::move(TRC);
+ if (TE)
+ TypoExprs.push_back(TE);
return TE;
}
diff --git a/lib/Sema/SemaModule.cpp b/lib/Sema/SemaModule.cpp
index 10de0ca91221..1fca351bfb09 100644
--- a/lib/Sema/SemaModule.cpp
+++ b/lib/Sema/SemaModule.cpp
@@ -31,6 +31,8 @@ static void checkModuleImportContext(Sema &S, Module *M,
ExternCLoc = LSD->getBeginLoc();
break;
case LinkageSpecDecl::lang_cxx:
+ case LinkageSpecDecl::lang_cxx_11:
+ case LinkageSpecDecl::lang_cxx_14:
break;
}
DC = LSD->getParent();
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index e5c014501431..ac810745d2f5 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -735,7 +735,7 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
return;
// If the ivar is private, and it's implicitly __unsafe_unretained
- // becaues of its type, then pretend it was actually implicitly
+ // because of its type, then pretend it was actually implicitly
// __strong. This is only sound because we're processing the
// property implementation before parsing any method bodies.
if (ivarLifetime == Qualifiers::OCL_ExplicitNone &&
@@ -2419,9 +2419,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
ObjCReturnsInnerPointerAttr::CreateImplicit(Context, Loc));
if (const SectionAttr *SA = property->getAttr<SectionAttr>())
- GetterMethod->addAttr(
- SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section,
- SA->getName(), Loc));
+ GetterMethod->addAttr(SectionAttr::CreateImplicit(
+ Context, SA->getName(), Loc, AttributeCommonInfo::AS_GNU,
+ SectionAttr::GNU_section));
if (getLangOpts().ObjCAutoRefCount)
CheckARCMethodDecl(GetterMethod);
@@ -2485,9 +2485,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
CD->addDecl(SetterMethod);
if (const SectionAttr *SA = property->getAttr<SectionAttr>())
- SetterMethod->addAttr(
- SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section,
- SA->getName(), Loc));
+ SetterMethod->addAttr(SectionAttr::CreateImplicit(
+ Context, SA->getName(), Loc, AttributeCommonInfo::AS_GNU,
+ SectionAttr::GNU_section));
// It's possible for the user to have set a very odd custom
// setter selector that causes it to have a method family.
if (getLangOpts().ObjCAutoRefCount)
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index bd68011c18b2..c7e0d2aee036 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -139,6 +139,7 @@ private:
/// clause, false otherwise.
llvm::Optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion;
unsigned AssociatedLoops = 1;
+ bool HasMutipleLoops = false;
const Decl *PossiblyLoopCounter = nullptr;
bool NowaitRegion = false;
bool CancelRegion = false;
@@ -169,7 +170,7 @@ private:
OpenMPClauseKind ClauseKindMode = OMPC_unknown;
Sema &SemaRef;
bool ForceCapturing = false;
- /// true if all the vaiables in the target executable directives must be
+ /// true if all the variables in the target executable directives must be
/// captured by reference.
bool ForceCaptureByReferenceInTargetExecutable = false;
CriticalsWithHintsTy Criticals;
@@ -521,6 +522,13 @@ public:
assert(!isStackEmpty() && "No directive at specified level.");
return getStackElemAtLevel(Level).Directive;
}
+ /// Returns the capture region at the specified level.
+ OpenMPDirectiveKind getCaptureRegion(unsigned Level,
+ unsigned OpenMPCaptureLevel) const {
+ SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
+ getOpenMPCaptureRegions(CaptureRegions, getDirective(Level));
+ return CaptureRegions[OpenMPCaptureLevel];
+ }
/// Returns parent directive.
OpenMPDirectiveKind getParentDirective() const {
const SharingMapTy *Parent = getSecondOnStackOrNull();
@@ -678,12 +686,19 @@ public:
/// Set collapse value for the region.
void setAssociatedLoops(unsigned Val) {
getTopOfStack().AssociatedLoops = Val;
+ if (Val > 1)
+ getTopOfStack().HasMutipleLoops = true;
}
/// Return collapse value for region.
unsigned getAssociatedLoops() const {
const SharingMapTy *Top = getTopOfStackOrNull();
return Top ? Top->AssociatedLoops : 0;
}
+ /// Returns true if the construct is associated with multiple loops.
+ bool hasMutipleLoops() const {
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->HasMutipleLoops : false;
+ }
/// Marks current target region as one with closely nested teams
/// region.
@@ -951,7 +966,8 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter,
// In a parallel construct, if no default clause is present, these
// variables are shared.
DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
- if (isOpenMPParallelDirective(DVar.DKind) ||
+ if ((isOpenMPParallelDirective(DVar.DKind) &&
+ !isOpenMPTaskLoopDirective(DVar.DKind)) ||
isOpenMPTeamsDirective(DVar.DKind)) {
DVar.CKind = OMPC_shared;
return DVar;
@@ -1332,7 +1348,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
}
const_iterator End = end();
if (!SemaRef.isOpenMPCapturedByRef(
- D, std::distance(ParentIterTarget, End))) {
+ D, std::distance(ParentIterTarget, End),
+ /*OpenMPCaptureLevel=*/0)) {
DVar.RefExpr =
buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(),
IterTarget->ConstructLoc);
@@ -1540,49 +1557,150 @@ static bool isOpenMPDeviceDelayedContext(Sema &S) {
!S.isInOpenMPDeclareTargetContext();
}
-/// Do we know that we will eventually codegen the given function?
-static bool isKnownEmitted(Sema &S, FunctionDecl *FD) {
- assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice &&
- "Expected OpenMP device compilation.");
- // Templates are emitted when they're instantiated.
- if (FD->isDependentContext())
- return false;
-
- if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
- FD->getCanonicalDecl()))
- return true;
-
- // Otherwise, the function is known-emitted if it's in our set of
- // known-emitted functions.
- return S.DeviceKnownEmittedFns.count(FD) > 0;
-}
+namespace {
+/// Status of the function emission on the host/device.
+enum class FunctionEmissionStatus {
+ Emitted,
+ Discarded,
+ Unknown,
+};
+} // anonymous namespace
Sema::DeviceDiagBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc,
unsigned DiagID) {
assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
"Expected OpenMP device compilation.");
- return DeviceDiagBuilder((isOpenMPDeviceDelayedContext(*this) &&
- !isKnownEmitted(*this, getCurFunctionDecl()))
- ? DeviceDiagBuilder::K_Deferred
- : DeviceDiagBuilder::K_Immediate,
- Loc, DiagID, getCurFunctionDecl(), *this);
+ FunctionEmissionStatus FES = getEmissionStatus(getCurFunctionDecl());
+ DeviceDiagBuilder::Kind Kind = DeviceDiagBuilder::K_Nop;
+ switch (FES) {
+ case FunctionEmissionStatus::Emitted:
+ Kind = DeviceDiagBuilder::K_Immediate;
+ break;
+ case FunctionEmissionStatus::Unknown:
+ Kind = isOpenMPDeviceDelayedContext(*this) ? DeviceDiagBuilder::K_Deferred
+ : DeviceDiagBuilder::K_Immediate;
+ break;
+ case FunctionEmissionStatus::TemplateDiscarded:
+ case FunctionEmissionStatus::OMPDiscarded:
+ Kind = DeviceDiagBuilder::K_Nop;
+ break;
+ case FunctionEmissionStatus::CUDADiscarded:
+ llvm_unreachable("CUDADiscarded unexpected in OpenMP device compilation");
+ break;
+ }
+
+ return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this);
}
-void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) {
+Sema::DeviceDiagBuilder Sema::diagIfOpenMPHostCode(SourceLocation Loc,
+ unsigned DiagID) {
+ assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice &&
+ "Expected OpenMP host compilation.");
+ FunctionEmissionStatus FES = getEmissionStatus(getCurFunctionDecl());
+ DeviceDiagBuilder::Kind Kind = DeviceDiagBuilder::K_Nop;
+ switch (FES) {
+ case FunctionEmissionStatus::Emitted:
+ Kind = DeviceDiagBuilder::K_Immediate;
+ break;
+ case FunctionEmissionStatus::Unknown:
+ Kind = DeviceDiagBuilder::K_Deferred;
+ break;
+ case FunctionEmissionStatus::TemplateDiscarded:
+ case FunctionEmissionStatus::OMPDiscarded:
+ case FunctionEmissionStatus::CUDADiscarded:
+ Kind = DeviceDiagBuilder::K_Nop;
+ break;
+ }
+
+ return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this);
+}
+
+void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee,
+ bool CheckForDelayedContext) {
assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
"Expected OpenMP device compilation.");
assert(Callee && "Callee may not be null.");
+ Callee = Callee->getMostRecentDecl();
FunctionDecl *Caller = getCurFunctionDecl();
+ // host only function are not available on the device.
+ if (Caller) {
+ FunctionEmissionStatus CallerS = getEmissionStatus(Caller);
+ FunctionEmissionStatus CalleeS = getEmissionStatus(Callee);
+ assert(CallerS != FunctionEmissionStatus::CUDADiscarded &&
+ CalleeS != FunctionEmissionStatus::CUDADiscarded &&
+ "CUDADiscarded unexpected in OpenMP device function check");
+ if ((CallerS == FunctionEmissionStatus::Emitted ||
+ (!isOpenMPDeviceDelayedContext(*this) &&
+ CallerS == FunctionEmissionStatus::Unknown)) &&
+ CalleeS == FunctionEmissionStatus::OMPDiscarded) {
+ StringRef HostDevTy = getOpenMPSimpleClauseTypeName(
+ OMPC_device_type, OMPC_DEVICE_TYPE_host);
+ Diag(Loc, diag::err_omp_wrong_device_function_call) << HostDevTy << 0;
+ Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
+ diag::note_omp_marked_device_type_here)
+ << HostDevTy;
+ return;
+ }
+ }
// If the caller is known-emitted, mark the callee as known-emitted.
// Otherwise, mark the call in our call graph so we can traverse it later.
- if (!isOpenMPDeviceDelayedContext(*this) ||
- (Caller && isKnownEmitted(*this, Caller)))
- markKnownEmitted(*this, Caller, Callee, Loc, isKnownEmitted);
+ if ((CheckForDelayedContext && !isOpenMPDeviceDelayedContext(*this)) ||
+ (!Caller && !CheckForDelayedContext) ||
+ (Caller && getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted))
+ markKnownEmitted(*this, Caller, Callee, Loc,
+ [CheckForDelayedContext](Sema &S, FunctionDecl *FD) {
+ return CheckForDelayedContext &&
+ S.getEmissionStatus(FD) ==
+ FunctionEmissionStatus::Emitted;
+ });
else if (Caller)
DeviceCallGraph[Caller].insert({Callee, Loc});
}
+void Sema::checkOpenMPHostFunction(SourceLocation Loc, FunctionDecl *Callee,
+ bool CheckCaller) {
+ assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice &&
+ "Expected OpenMP host compilation.");
+ assert(Callee && "Callee may not be null.");
+ Callee = Callee->getMostRecentDecl();
+ FunctionDecl *Caller = getCurFunctionDecl();
+
+ // device only function are not available on the host.
+ if (Caller) {
+ FunctionEmissionStatus CallerS = getEmissionStatus(Caller);
+ FunctionEmissionStatus CalleeS = getEmissionStatus(Callee);
+ assert(
+ (LangOpts.CUDA || (CallerS != FunctionEmissionStatus::CUDADiscarded &&
+ CalleeS != FunctionEmissionStatus::CUDADiscarded)) &&
+ "CUDADiscarded unexpected in OpenMP host function check");
+ if (CallerS == FunctionEmissionStatus::Emitted &&
+ CalleeS == FunctionEmissionStatus::OMPDiscarded) {
+ StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName(
+ OMPC_device_type, OMPC_DEVICE_TYPE_nohost);
+ Diag(Loc, diag::err_omp_wrong_device_function_call) << NoHostDevTy << 1;
+ Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
+ diag::note_omp_marked_device_type_here)
+ << NoHostDevTy;
+ return;
+ }
+ }
+ // If the caller is known-emitted, mark the callee as known-emitted.
+ // Otherwise, mark the call in our call graph so we can traverse it later.
+ if (!shouldIgnoreInHostDeviceCheck(Callee)) {
+ if ((!CheckCaller && !Caller) ||
+ (Caller &&
+ getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted))
+ markKnownEmitted(
+ *this, Caller, Callee, Loc, [CheckCaller](Sema &S, FunctionDecl *FD) {
+ return CheckCaller &&
+ S.getEmissionStatus(FD) == FunctionEmissionStatus::Emitted;
+ });
+ else if (Caller)
+ DeviceCallGraph[Caller].insert({Callee, Loc});
+ }
+}
+
void Sema::checkOpenMPDeviceExpr(const Expr *E) {
assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice &&
"OpenMP device compilation mode is expected.");
@@ -1598,7 +1716,8 @@ void Sema::checkOpenMPDeviceExpr(const Expr *E) {
<< Context.getTargetInfo().getTriple().str() << E->getSourceRange();
}
-bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
+bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
+ unsigned OpenMPCaptureLevel) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
ASTContext &Ctx = getASTContext();
@@ -1608,6 +1727,7 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
D = cast<ValueDecl>(D->getCanonicalDecl());
QualType Ty = D->getType();
+ bool IsVariableUsedInMapClause = false;
if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level)) {
// This table summarizes how a given variable should be passed to the device
// given its type and the clauses where it appears. This table is based on
@@ -1669,7 +1789,6 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
// Locate map clauses and see if the variable being captured is referred to
// in any of those clauses. Here we only care about variables, not fields,
// because fields are part of aggregates.
- bool IsVariableUsedInMapClause = false;
bool IsVariableAssociatedWithSection = false;
DSAStack->checkMappableExprComponentListsForDeclAtLevel(
@@ -1727,10 +1846,13 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
if (IsByRef && Ty.getNonReferenceType()->isScalarType()) {
IsByRef =
- !DSAStack->hasExplicitDSA(
- D,
- [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; },
- Level, /*NotLastprivate=*/true) &&
+ ((IsVariableUsedInMapClause &&
+ DSAStack->getCaptureRegion(Level, OpenMPCaptureLevel) ==
+ OMPD_target) ||
+ !DSAStack->hasExplicitDSA(
+ D,
+ [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; },
+ Level, /*NotLastprivate=*/true)) &&
// If the variable is artificial and must be captured by value - try to
// capture by value.
!(isa<OMPCapturedExprDecl>(D) && !D->hasAttr<OMPCaptureNoInitAttr>() &&
@@ -1788,7 +1910,8 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
if (isInOpenMPDeclareTargetContext()) {
// Try to mark variable as declare target if it is used in capturing
// regions.
- if (!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
+ if (LangOpts.OpenMP <= 45 &&
+ !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
checkDeclIsAllowedInOpenMPTarget(nullptr, VD);
return nullptr;
} else if (isInOpenMPTargetExecutionDirective()) {
@@ -1858,6 +1981,14 @@ void Sema::startOpenMPLoop() {
DSAStack->loopInit();
}
+void Sema::startOpenMPCXXRangeFor() {
+ assert(LangOpts.OpenMP && "OpenMP must be enabled.");
+ if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
+ DSAStack->resetPossibleLoopCounter();
+ DSAStack->loopStart();
+ }
+}
+
bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
@@ -1874,6 +2005,13 @@ bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const {
!isOpenMPSimdDirective(DSAStack->getCurrentDirective()))
return true;
}
+ if (const auto *VD = dyn_cast<VarDecl>(D)) {
+ if (DSAStack->isThreadPrivate(const_cast<VarDecl *>(VD)) &&
+ DSAStack->isForceVarCapturing() &&
+ !DSAStack->hasExplicitDSA(
+ D, [](OpenMPClauseKind K) { return K == OMPC_copyin; }, Level))
+ return true;
+ }
return DSAStack->hasExplicitDSA(
D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) ||
(DSAStack->isClauseParsingMode() &&
@@ -1937,6 +2075,54 @@ bool Sema::isOpenMPTargetCapturedDecl(const ValueDecl *D,
void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; }
+void Sema::finalizeOpenMPDelayedAnalysis() {
+ assert(LangOpts.OpenMP && "Expected OpenMP compilation mode.");
+ // Diagnose implicit declare target functions and their callees.
+ for (const auto &CallerCallees : DeviceCallGraph) {
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(
+ CallerCallees.getFirst()->getMostRecentDecl());
+ // Ignore host functions during device analyzis.
+ if (LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_Host)
+ continue;
+ // Ignore nohost functions during host analyzis.
+ if (!LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
+ continue;
+ for (const std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation>
+ &Callee : CallerCallees.getSecond()) {
+ const FunctionDecl *FD = Callee.first->getMostRecentDecl();
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(FD);
+ if (LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_Host) {
+ // Diagnose host function called during device codegen.
+ StringRef HostDevTy = getOpenMPSimpleClauseTypeName(
+ OMPC_device_type, OMPC_DEVICE_TYPE_host);
+ Diag(Callee.second, diag::err_omp_wrong_device_function_call)
+ << HostDevTy << 0;
+ Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
+ diag::note_omp_marked_device_type_here)
+ << HostDevTy;
+ continue;
+ }
+ if (!LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) {
+ // Diagnose nohost function called during host codegen.
+ StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName(
+ OMPC_device_type, OMPC_DEVICE_TYPE_nohost);
+ Diag(Callee.second, diag::err_omp_wrong_device_function_call)
+ << NoHostDevTy << 1;
+ Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
+ diag::note_omp_marked_device_type_here)
+ << NoHostDevTy;
+ continue;
+ }
+ }
+ }
+}
+
void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind,
const DeclarationNameInfo &DirName,
Scope *CurScope, SourceLocation Loc) {
@@ -2034,7 +2220,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<VarDeclFilterCCC>(*this);
+ return std::make_unique<VarDeclFilterCCC>(*this);
}
};
@@ -2056,7 +2242,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<VarOrFuncDeclFilterCCC>(*this);
+ return std::make_unique<VarOrFuncDeclFilterCCC>(*this);
}
};
@@ -2944,18 +3130,19 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
+ Params, /*OpenMPCaptureLevel=*/0);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
Sema::CapturedParamNameType ParamsTarget[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsTarget);
+ ParamsTarget, /*OpenMPCaptureLevel=*/1);
Sema::CapturedParamNameType ParamsTeamsOrParallel[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
std::make_pair(".bound_tid.", KmpInt32PtrTy),
@@ -2964,7 +3151,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// Start a captured region for 'teams' or 'parallel'. Both regions have
// the same implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsTeamsOrParallel);
+ ParamsTeamsOrParallel, /*OpenMPCaptureLevel=*/2);
break;
}
case OMPD_target:
@@ -2988,14 +3175,16 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
+ Params, /*OpenMPCaptureLevel=*/0);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- std::make_pair(StringRef(), QualType()));
+ std::make_pair(StringRef(), QualType()),
+ /*OpenMPCaptureLevel=*/1);
break;
}
case OMPD_simd:
@@ -3044,11 +3233,14 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
break;
}
case OMPD_taskloop:
- case OMPD_taskloop_simd: {
+ case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd: {
QualType KmpInt32Ty =
Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1)
.withConst();
@@ -3086,7 +3278,58 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
+ break;
+ }
+ case OMPD_parallel_master_taskloop: {
+ QualType KmpInt32Ty =
+ Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1)
+ .withConst();
+ QualType KmpUInt64Ty =
+ Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0)
+ .withConst();
+ QualType KmpInt64Ty =
+ Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1)
+ .withConst();
+ QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict();
+ QualType KmpInt32PtrTy =
+ Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
+ Sema::CapturedParamNameType ParamsParallel[] = {
+ std::make_pair(".global_tid.", KmpInt32PtrTy),
+ std::make_pair(".bound_tid.", KmpInt32PtrTy),
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ // Start a captured region for 'parallel'.
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ ParamsParallel, /*OpenMPCaptureLevel=*/1);
+ QualType Args[] = {VoidPtrTy};
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.Variadic = true;
+ QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI);
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(".global_tid.", KmpInt32Ty),
+ std::make_pair(".part_id.", KmpInt32PtrTy),
+ std::make_pair(".privates.", VoidPtrTy),
+ std::make_pair(
+ ".copy_fn.",
+ Context.getPointerType(CopyFnType).withConst().withRestrict()),
+ std::make_pair(".task_t.", Context.VoidPtrTy.withConst()),
+ std::make_pair(".lb.", KmpUInt64Ty),
+ std::make_pair(".ub.", KmpUInt64Ty),
+ std::make_pair(".st.", KmpInt64Ty),
+ std::make_pair(".liter.", KmpInt32Ty),
+ std::make_pair(".reductions.", VoidPtrTy),
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params, /*OpenMPCaptureLevel=*/2);
+ // Mark this captured region as inlined, because we don't use outlined
+ // function directly.
+ getCurCapturedRegion()->TheCapturedDecl->addAttr(
+ AlwaysInlineAttr::CreateImplicit(
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
break;
}
case OMPD_distribute_parallel_for_simd:
@@ -3127,18 +3370,19 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
+ Params, /*OpenMPCaptureLevel=*/0);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
Sema::CapturedParamNameType ParamsTarget[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsTarget);
+ ParamsTarget, /*OpenMPCaptureLevel=*/1);
Sema::CapturedParamNameType ParamsTeams[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
@@ -3147,7 +3391,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsTeams);
+ ParamsTeams, /*OpenMPCaptureLevel=*/2);
Sema::CapturedParamNameType ParamsParallel[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
@@ -3159,7 +3403,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// Start a captured region for 'teams' or 'parallel'. Both regions have
// the same implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsParallel);
+ ParamsParallel, /*OpenMPCaptureLevel=*/3);
break;
}
@@ -3176,7 +3420,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsTeams);
+ ParamsTeams, /*OpenMPCaptureLevel=*/0);
Sema::CapturedParamNameType ParamsParallel[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
@@ -3188,7 +3432,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// Start a captured region for 'teams' or 'parallel'. Both regions have
// the same implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsParallel);
+ ParamsParallel, /*OpenMPCaptureLevel=*/1);
break;
}
case OMPD_target_update:
@@ -3218,7 +3462,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
break;
}
case OMPD_threadprivate:
@@ -3235,12 +3480,17 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_requires:
+ case OMPD_declare_variant:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
}
+int Sema::getNumberOfConstructScopes(unsigned Level) const {
+ return getOpenMPCaptureLevels(DSAStack->getDirective(Level));
+}
+
int Sema::getOpenMPCaptureLevels(OpenMPDirectiveKind DKind) {
SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
getOpenMPCaptureRegions(CaptureRegions, DKind);
@@ -3670,7 +3920,10 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
// OpenMP [2.16, Nesting of Regions]
// If specified, a teams construct must be contained within a target
// construct.
- NestingProhibited = ParentRegion != OMPD_target;
+ NestingProhibited =
+ (SemaRef.LangOpts.OpenMP <= 45 && ParentRegion != OMPD_target) ||
+ (SemaRef.LangOpts.OpenMP >= 50 && ParentRegion != OMPD_unknown &&
+ ParentRegion != OMPD_target);
OrphanSeen = ParentRegion == OMPD_unknown;
Recommend = ShouldBeInTargetRegion;
}
@@ -4214,6 +4467,22 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_taskloop);
break;
+ case OMPD_master_taskloop:
+ Res = ActOnOpenMPMasterTaskLoopDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ break;
+ case OMPD_master_taskloop_simd:
+ Res = ActOnOpenMPMasterTaskLoopSimdDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ break;
+ case OMPD_parallel_master_taskloop:
+ Res = ActOnOpenMPParallelMasterTaskLoopDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ AllowedNameModifiers.push_back(OMPD_parallel);
+ break;
case OMPD_distribute:
Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
@@ -4301,6 +4570,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_requires:
+ case OMPD_declare_variant:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
@@ -4326,18 +4596,22 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
continue;
case OMPC_schedule:
break;
+ case OMPC_grainsize:
+ case OMPC_num_tasks:
+ case OMPC_final:
+ case OMPC_priority:
+ // Do not analyze if no parent parallel directive.
+ if (isOpenMPParallelDirective(DSAStack->getCurrentDirective()))
+ break;
+ continue;
case OMPC_ordered:
case OMPC_device:
case OMPC_num_teams:
case OMPC_thread_limit:
- case OMPC_priority:
- case OMPC_grainsize:
- case OMPC_num_tasks:
case OMPC_hint:
case OMPC_collapse:
case OMPC_safelen:
case OMPC_simdlen:
- case OMPC_final:
case OMPC_default:
case OMPC_proc_bind:
case OMPC_private:
@@ -4381,6 +4655,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Unexpected clause");
}
for (Stmt *CC : C->children()) {
@@ -4437,8 +4713,10 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
if (!DG || DG.get().isNull())
return DeclGroupPtrTy();
+ const int SimdId = 0;
if (!DG.get().isSingleDecl()) {
- Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd);
+ Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd_variant)
+ << SimdId;
return DG;
}
Decl *ADecl = DG.get().getSingleDecl();
@@ -4447,7 +4725,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
auto *FD = dyn_cast<FunctionDecl>(ADecl);
if (!FD) {
- Diag(ADecl->getLocation(), diag::err_omp_function_expected);
+ Diag(ADecl->getLocation(), diag::err_omp_function_expected) << SimdId;
return DeclGroupPtrTy();
}
@@ -4669,7 +4947,266 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
const_cast<unsigned *>(LinModifiers.data()), LinModifiers.size(),
NewSteps.data(), NewSteps.size(), SR);
ADecl->addAttr(NewAttr);
- return ConvertDeclToDeclGroup(ADecl);
+ return DG;
+}
+
+Optional<std::pair<FunctionDecl *, Expr *>>
+Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
+ Expr *VariantRef, SourceRange SR) {
+ if (!DG || DG.get().isNull())
+ return None;
+
+ const int VariantId = 1;
+ // Must be applied only to single decl.
+ if (!DG.get().isSingleDecl()) {
+ Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd_variant)
+ << VariantId << SR;
+ return None;
+ }
+ Decl *ADecl = DG.get().getSingleDecl();
+ if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl))
+ ADecl = FTD->getTemplatedDecl();
+
+ // Decl must be a function.
+ auto *FD = dyn_cast<FunctionDecl>(ADecl);
+ if (!FD) {
+ Diag(ADecl->getLocation(), diag::err_omp_function_expected)
+ << VariantId << SR;
+ return None;
+ }
+
+ auto &&HasMultiVersionAttributes = [](const FunctionDecl *FD) {
+ return FD->hasAttrs() &&
+ (FD->hasAttr<CPUDispatchAttr>() || FD->hasAttr<CPUSpecificAttr>() ||
+ FD->hasAttr<TargetAttr>());
+ };
+ // OpenMP is not compatible with CPU-specific attributes.
+ if (HasMultiVersionAttributes(FD)) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_incompat_attributes)
+ << SR;
+ return None;
+ }
+
+ // Allow #pragma omp declare variant only if the function is not used.
+ if (FD->isUsed(false))
+ Diag(SR.getBegin(), diag::warn_omp_declare_variant_after_used)
+ << FD->getLocation();
+
+ // Check if the function was emitted already.
+ const FunctionDecl *Definition;
+ if (!FD->isThisDeclarationADefinition() && FD->isDefined(Definition) &&
+ (LangOpts.EmitAllDecls || Context.DeclMustBeEmitted(Definition)))
+ Diag(SR.getBegin(), diag::warn_omp_declare_variant_after_emitted)
+ << FD->getLocation();
+
+ // The VariantRef must point to function.
+ if (!VariantRef) {
+ Diag(SR.getBegin(), diag::err_omp_function_expected) << VariantId;
+ return None;
+ }
+
+ // Do not check templates, wait until instantiation.
+ if (VariantRef->isTypeDependent() || VariantRef->isValueDependent() ||
+ VariantRef->containsUnexpandedParameterPack() ||
+ VariantRef->isInstantiationDependent() || FD->isDependentContext())
+ return std::make_pair(FD, VariantRef);
+
+ // Convert VariantRef expression to the type of the original function to
+ // resolve possible conflicts.
+ ExprResult VariantRefCast;
+ if (LangOpts.CPlusPlus) {
+ QualType FnPtrType;
+ auto *Method = dyn_cast<CXXMethodDecl>(FD);
+ if (Method && !Method->isStatic()) {
+ const Type *ClassType =
+ Context.getTypeDeclType(Method->getParent()).getTypePtr();
+ FnPtrType = Context.getMemberPointerType(FD->getType(), ClassType);
+ ExprResult ER;
+ {
+ // Build adrr_of unary op to correctly handle type checks for member
+ // functions.
+ Sema::TentativeAnalysisScope Trap(*this);
+ ER = CreateBuiltinUnaryOp(VariantRef->getBeginLoc(), UO_AddrOf,
+ VariantRef);
+ }
+ if (!ER.isUsable()) {
+ Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
+ << VariantId << VariantRef->getSourceRange();
+ return None;
+ }
+ VariantRef = ER.get();
+ } else {
+ FnPtrType = Context.getPointerType(FD->getType());
+ }
+ ImplicitConversionSequence ICS =
+ TryImplicitConversion(VariantRef, FnPtrType.getUnqualifiedType(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*InOverloadResolution=*/false,
+ /*CStyle=*/false,
+ /*AllowObjCWritebackConversion=*/false);
+ if (ICS.isFailure()) {
+ Diag(VariantRef->getExprLoc(),
+ diag::err_omp_declare_variant_incompat_types)
+ << VariantRef->getType() << FnPtrType << VariantRef->getSourceRange();
+ return None;
+ }
+ VariantRefCast = PerformImplicitConversion(
+ VariantRef, FnPtrType.getUnqualifiedType(), AA_Converting);
+ if (!VariantRefCast.isUsable())
+ return None;
+ // Drop previously built artificial addr_of unary op for member functions.
+ if (Method && !Method->isStatic()) {
+ Expr *PossibleAddrOfVariantRef = VariantRefCast.get();
+ if (auto *UO = dyn_cast<UnaryOperator>(
+ PossibleAddrOfVariantRef->IgnoreImplicit()))
+ VariantRefCast = UO->getSubExpr();
+ }
+ } else {
+ VariantRefCast = VariantRef;
+ }
+
+ ExprResult ER = CheckPlaceholderExpr(VariantRefCast.get());
+ if (!ER.isUsable() ||
+ !ER.get()->IgnoreParenImpCasts()->getType()->isFunctionType()) {
+ Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
+ << VariantId << VariantRef->getSourceRange();
+ return None;
+ }
+
+ // The VariantRef must point to function.
+ auto *DRE = dyn_cast<DeclRefExpr>(ER.get()->IgnoreParenImpCasts());
+ if (!DRE) {
+ Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
+ << VariantId << VariantRef->getSourceRange();
+ return None;
+ }
+ auto *NewFD = dyn_cast_or_null<FunctionDecl>(DRE->getDecl());
+ if (!NewFD) {
+ Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
+ << VariantId << VariantRef->getSourceRange();
+ return None;
+ }
+
+ // Check if variant function is not marked with declare variant directive.
+ if (NewFD->hasAttrs() && NewFD->hasAttr<OMPDeclareVariantAttr>()) {
+ Diag(VariantRef->getExprLoc(),
+ diag::warn_omp_declare_variant_marked_as_declare_variant)
+ << VariantRef->getSourceRange();
+ SourceRange SR =
+ NewFD->specific_attr_begin<OMPDeclareVariantAttr>()->getRange();
+ Diag(SR.getBegin(), diag::note_omp_marked_declare_variant_here) << SR;
+ return None;
+ }
+
+ enum DoesntSupport {
+ VirtFuncs = 1,
+ Constructors = 3,
+ Destructors = 4,
+ DeletedFuncs = 5,
+ DefaultedFuncs = 6,
+ ConstexprFuncs = 7,
+ ConstevalFuncs = 8,
+ };
+ if (const auto *CXXFD = dyn_cast<CXXMethodDecl>(FD)) {
+ if (CXXFD->isVirtual()) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << VirtFuncs;
+ return None;
+ }
+
+ if (isa<CXXConstructorDecl>(FD)) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << Constructors;
+ return None;
+ }
+
+ if (isa<CXXDestructorDecl>(FD)) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << Destructors;
+ return None;
+ }
+ }
+
+ if (FD->isDeleted()) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << DeletedFuncs;
+ return None;
+ }
+
+ if (FD->isDefaulted()) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << DefaultedFuncs;
+ return None;
+ }
+
+ if (FD->isConstexpr()) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs);
+ return None;
+ }
+
+ // Check general compatibility.
+ if (areMultiversionVariantFunctionsCompatible(
+ FD, NewFD, PDiag(diag::err_omp_declare_variant_noproto),
+ PartialDiagnosticAt(
+ SR.getBegin(),
+ PDiag(diag::note_omp_declare_variant_specified_here) << SR),
+ PartialDiagnosticAt(
+ VariantRef->getExprLoc(),
+ PDiag(diag::err_omp_declare_variant_doesnt_support)),
+ PartialDiagnosticAt(VariantRef->getExprLoc(),
+ PDiag(diag::err_omp_declare_variant_diff)
+ << FD->getLocation()),
+ /*TemplatesSupported=*/true, /*ConstexprSupported=*/false,
+ /*CLinkageMayDiffer=*/true))
+ return None;
+ return std::make_pair(FD, cast<Expr>(DRE));
+}
+
+void Sema::ActOnOpenMPDeclareVariantDirective(
+ FunctionDecl *FD, Expr *VariantRef, SourceRange SR,
+ const Sema::OpenMPDeclareVariantCtsSelectorData &Data) {
+ if (Data.CtxSet == OMPDeclareVariantAttr::CtxSetUnknown ||
+ Data.Ctx == OMPDeclareVariantAttr::CtxUnknown)
+ return;
+ Expr *Score = nullptr;
+ OMPDeclareVariantAttr::ScoreType ST = OMPDeclareVariantAttr::ScoreUnknown;
+ if (Data.CtxScore.isUsable()) {
+ ST = OMPDeclareVariantAttr::ScoreSpecified;
+ Score = Data.CtxScore.get();
+ if (!Score->isTypeDependent() && !Score->isValueDependent() &&
+ !Score->isInstantiationDependent() &&
+ !Score->containsUnexpandedParameterPack()) {
+ llvm::APSInt Result;
+ ExprResult ICE = VerifyIntegerConstantExpression(Score, &Result);
+ if (ICE.isInvalid())
+ return;
+ }
+ }
+ auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit(
+ Context, VariantRef, Score, Data.CtxSet, ST, Data.Ctx,
+ Data.ImplVendors.begin(), Data.ImplVendors.size(), SR);
+ FD->addAttr(NewAttr);
+}
+
+void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc,
+ FunctionDecl *Func,
+ bool MightBeOdrUse) {
+ assert(LangOpts.OpenMP && "Expected OpenMP mode.");
+
+ if (!Func->isDependentContext() && Func->hasAttrs()) {
+ for (OMPDeclareVariantAttr *A :
+ Func->specific_attrs<OMPDeclareVariantAttr>()) {
+ // TODO: add checks for active OpenMP context where possible.
+ Expr *VariantRef = A->getVariantFuncRef();
+ auto *DRE = dyn_cast<DeclRefExpr>(VariantRef->IgnoreParenImpCasts());
+ auto *F = cast<FunctionDecl>(DRE->getDecl());
+ if (!F->isDefined() && F->isTemplateInstantiation())
+ InstantiateFunctionDefinition(Loc, F->getFirstDecl());
+ MarkFunctionReferenced(Loc, F, MightBeOdrUse);
+ }
+ }
}
StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
@@ -4694,6 +5231,54 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
}
namespace {
+/// Iteration space of a single for loop.
+struct LoopIterationSpace final {
+ /// True if the condition operator is the strict compare operator (<, > or
+ /// !=).
+ bool IsStrictCompare = false;
+ /// Condition of the loop.
+ Expr *PreCond = nullptr;
+ /// This expression calculates the number of iterations in the loop.
+ /// It is always possible to calculate it before starting the loop.
+ Expr *NumIterations = nullptr;
+ /// The loop counter variable.
+ Expr *CounterVar = nullptr;
+ /// Private loop counter variable.
+ Expr *PrivateCounterVar = nullptr;
+ /// This is initializer for the initial value of #CounterVar.
+ Expr *CounterInit = nullptr;
+ /// This is step for the #CounterVar used to generate its update:
+ /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration.
+ Expr *CounterStep = nullptr;
+ /// Should step be subtracted?
+ bool Subtract = false;
+ /// Source range of the loop init.
+ SourceRange InitSrcRange;
+ /// Source range of the loop condition.
+ SourceRange CondSrcRange;
+ /// Source range of the loop increment.
+ SourceRange IncSrcRange;
+ /// Minimum value that can have the loop control variable. Used to support
+ /// non-rectangular loops. Applied only for LCV with the non-iterator types,
+ /// since only such variables can be used in non-loop invariant expressions.
+ Expr *MinValue = nullptr;
+ /// Maximum value that can have the loop control variable. Used to support
+ /// non-rectangular loops. Applied only for LCV with the non-iterator type,
+ /// since only such variables can be used in non-loop invariant expressions.
+ Expr *MaxValue = nullptr;
+ /// true, if the lower bound depends on the outer loop control var.
+ bool IsNonRectangularLB = false;
+ /// true, if the upper bound depends on the outer loop control var.
+ bool IsNonRectangularUB = false;
+ /// Index of the loop this loop depends on and forms non-rectangular loop
+ /// nest.
+ unsigned LoopDependentIdx = 0;
+ /// Final condition for the non-rectangular loop nest support. It is used to
+ /// check that the number of iterations for this particular counter must be
+ /// finished.
+ Expr *FinalCondition = nullptr;
+};
+
/// Helper class for checking canonical form of the OpenMP loops and
/// extracting iteration space of each loop in the loop nest, that will be used
/// for IR generation.
@@ -4743,6 +5328,9 @@ class OpenMPIterationSpaceChecker {
Optional<unsigned> CondDependOnLC;
/// Checks if the provide statement depends on the loop counter.
Optional<unsigned> doesDependOnLoopCounter(const Stmt *S, bool IsInitializer);
+ /// Original condition required for checking of the exit condition for
+ /// non-rectangular loop.
+ Expr *Condition = nullptr;
public:
OpenMPIterationSpaceChecker(Sema &SemaRef, DSAStackTy &Stack,
@@ -4774,7 +5362,7 @@ public:
bool isStrictTestOp() const { return TestIsStrictOp; }
/// Build the expression to calculate the number of iterations.
Expr *buildNumIterations(
- Scope *S, const bool LimitedType,
+ Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const;
/// Build the precondition expression for the loops.
Expr *
@@ -4798,8 +5386,21 @@ public:
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
SourceLocation Loc, Expr *Inc = nullptr,
OverloadedOperatorKind OOK = OO_Amp);
+ /// Builds the minimum value for the loop counter.
+ std::pair<Expr *, Expr *> buildMinMaxValues(
+ Scope *S, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const;
+ /// Builds final condition for the non-rectangular loops.
+ Expr *buildFinalCondition(Scope *S) const;
/// Return true if any expression is dependent.
bool dependent() const;
+ /// Returns true if the initializer forms non-rectangular loop.
+ bool doesInitDependOnLC() const { return InitDependOnLC.hasValue(); }
+ /// Returns true if the condition forms non-rectangular loop.
+ bool doesCondDependOnLC() const { return CondDependOnLC.hasValue(); }
+ /// Returns index of the loop we depend on (starting from 1), or 0 otherwise.
+ unsigned getLoopDependentIdx() const {
+ return InitDependOnLC.getValueOr(CondDependOnLC.getValueOr(0));
+ }
private:
/// Check the right-hand side of an assignment in the increment
@@ -4998,9 +5599,9 @@ public:
return false;
}
bool VisitStmt(const Stmt *S) {
- bool Res = true;
+ bool Res = false;
for (const Stmt *Child : S->children())
- Res = Child && Visit(Child) && Res;
+ Res = (Child && Visit(Child)) || Res;
return Res;
}
explicit LoopCounterRefChecker(Sema &SemaRef, DSAStackTy &Stack,
@@ -5142,14 +5743,17 @@ static const ValueDecl *getInitLCDecl(const Expr *E) {
bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
// Check test-expr for canonical form, save upper-bound UB, flags for
// less/greater and for strict/non-strict comparison.
- // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following:
+ // OpenMP [2.9] Canonical loop form. Test-expr may be one of the following:
// var relational-op b
// b relational-op var
//
+ bool IneqCondIsCanonical = SemaRef.getLangOpts().OpenMP >= 50;
if (!S) {
- SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << LCDecl;
+ SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond)
+ << (IneqCondIsCanonical ? 1 : 0) << LCDecl;
return true;
}
+ Condition = S;
S = getExprAsWritten(S);
SourceLocation CondLoc = S->getBeginLoc();
if (auto *BO = dyn_cast<BinaryOperator>(S)) {
@@ -5164,12 +5768,11 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
(BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE),
(BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT),
BO->getSourceRange(), BO->getOperatorLoc());
- } else if (BO->getOpcode() == BO_NE)
- return setUB(getInitLCDecl(BO->getLHS()) == LCDecl ?
- BO->getRHS() : BO->getLHS(),
- /*LessOp=*/llvm::None,
- /*StrictOp=*/true,
- BO->getSourceRange(), BO->getOperatorLoc());
+ } else if (IneqCondIsCanonical && BO->getOpcode() == BO_NE)
+ return setUB(
+ getInitLCDecl(BO->getLHS()) == LCDecl ? BO->getRHS() : BO->getLHS(),
+ /*LessOp=*/llvm::None,
+ /*StrictOp=*/true, BO->getSourceRange(), BO->getOperatorLoc());
} else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(S)) {
if (CE->getNumArgs() == 2) {
auto Op = CE->getOperator();
@@ -5188,12 +5791,12 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
CE->getOperatorLoc());
break;
case OO_ExclaimEqual:
- return setUB(getInitLCDecl(CE->getArg(0)) == LCDecl ?
- CE->getArg(1) : CE->getArg(0),
- /*LessOp=*/llvm::None,
- /*StrictOp=*/true,
- CE->getSourceRange(),
- CE->getOperatorLoc());
+ if (IneqCondIsCanonical)
+ return setUB(getInitLCDecl(CE->getArg(0)) == LCDecl ? CE->getArg(1)
+ : CE->getArg(0),
+ /*LessOp=*/llvm::None,
+ /*StrictOp=*/true, CE->getSourceRange(),
+ CE->getOperatorLoc());
break;
default:
break;
@@ -5203,7 +5806,7 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
if (dependent() || SemaRef.CurContext->isDependentContext())
return false;
SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond)
- << S->getSourceRange() << LCDecl;
+ << (IneqCondIsCanonical ? 1 : 0) << S->getSourceRange() << LCDecl;
return true;
}
@@ -5336,15 +5939,177 @@ tryBuildCapture(Sema &SemaRef, Expr *Capture,
/// Build the expression to calculate the number of iterations.
Expr *OpenMPIterationSpaceChecker::buildNumIterations(
- Scope *S, const bool LimitedType,
+ Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
ExprResult Diff;
QualType VarType = LCDecl->getType().getNonReferenceType();
if (VarType->isIntegerType() || VarType->isPointerType() ||
SemaRef.getLangOpts().CPlusPlus) {
+ Expr *LBVal = LB;
+ Expr *UBVal = UB;
+ // LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) :
+ // max(LB(MinVal), LB(MaxVal))
+ if (InitDependOnLC) {
+ const LoopIterationSpace &IS =
+ ResultIterSpaces[ResultIterSpaces.size() - 1 -
+ InitDependOnLC.getValueOr(
+ CondDependOnLC.getValueOr(0))];
+ if (!IS.MinValue || !IS.MaxValue)
+ return nullptr;
+ // OuterVar = Min
+ ExprResult MinValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue);
+ if (!MinValue.isUsable())
+ return nullptr;
+
+ ExprResult LBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MinValue.get());
+ if (!LBMinVal.isUsable())
+ return nullptr;
+ // OuterVar = Min, LBVal
+ LBMinVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMinVal.get(), LBVal);
+ if (!LBMinVal.isUsable())
+ return nullptr;
+ // (OuterVar = Min, LBVal)
+ LBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMinVal.get());
+ if (!LBMinVal.isUsable())
+ return nullptr;
+
+ // OuterVar = Max
+ ExprResult MaxValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue);
+ if (!MaxValue.isUsable())
+ return nullptr;
+
+ ExprResult LBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MaxValue.get());
+ if (!LBMaxVal.isUsable())
+ return nullptr;
+ // OuterVar = Max, LBVal
+ LBMaxVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal);
+ if (!LBMaxVal.isUsable())
+ return nullptr;
+ // (OuterVar = Max, LBVal)
+ LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get());
+ if (!LBMaxVal.isUsable())
+ return nullptr;
+
+ Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get();
+ Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get();
+ if (!LBMin || !LBMax)
+ return nullptr;
+ // LB(MinVal) < LB(MaxVal)
+ ExprResult MinLessMaxRes =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax);
+ if (!MinLessMaxRes.isUsable())
+ return nullptr;
+ Expr *MinLessMax =
+ tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get();
+ if (!MinLessMax)
+ return nullptr;
+ if (TestIsLessOp.getValue()) {
+ // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal),
+ // LB(MaxVal))
+ ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc,
+ MinLessMax, LBMin, LBMax);
+ if (!MinLB.isUsable())
+ return nullptr;
+ LBVal = MinLB.get();
+ } else {
+ // LB(MinVal) < LB(MaxVal) ? LB(MaxVal) : LB(MinVal) - max(LB(MinVal),
+ // LB(MaxVal))
+ ExprResult MaxLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc,
+ MinLessMax, LBMax, LBMin);
+ if (!MaxLB.isUsable())
+ return nullptr;
+ LBVal = MaxLB.get();
+ }
+ }
+ // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) :
+ // min(UB(MinVal), UB(MaxVal))
+ if (CondDependOnLC) {
+ const LoopIterationSpace &IS =
+ ResultIterSpaces[ResultIterSpaces.size() - 1 -
+ InitDependOnLC.getValueOr(
+ CondDependOnLC.getValueOr(0))];
+ if (!IS.MinValue || !IS.MaxValue)
+ return nullptr;
+ // OuterVar = Min
+ ExprResult MinValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue);
+ if (!MinValue.isUsable())
+ return nullptr;
+
+ ExprResult UBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MinValue.get());
+ if (!UBMinVal.isUsable())
+ return nullptr;
+ // OuterVar = Min, UBVal
+ UBMinVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMinVal.get(), UBVal);
+ if (!UBMinVal.isUsable())
+ return nullptr;
+ // (OuterVar = Min, UBVal)
+ UBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMinVal.get());
+ if (!UBMinVal.isUsable())
+ return nullptr;
+
+ // OuterVar = Max
+ ExprResult MaxValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue);
+ if (!MaxValue.isUsable())
+ return nullptr;
+
+ ExprResult UBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MaxValue.get());
+ if (!UBMaxVal.isUsable())
+ return nullptr;
+ // OuterVar = Max, UBVal
+ UBMaxVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal);
+ if (!UBMaxVal.isUsable())
+ return nullptr;
+ // (OuterVar = Max, UBVal)
+ UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get());
+ if (!UBMaxVal.isUsable())
+ return nullptr;
+
+ Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get();
+ Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get();
+ if (!UBMin || !UBMax)
+ return nullptr;
+ // UB(MinVal) > UB(MaxVal)
+ ExprResult MinGreaterMaxRes =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax);
+ if (!MinGreaterMaxRes.isUsable())
+ return nullptr;
+ Expr *MinGreaterMax =
+ tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get();
+ if (!MinGreaterMax)
+ return nullptr;
+ if (TestIsLessOp.getValue()) {
+ // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal),
+ // UB(MaxVal))
+ ExprResult MaxUB = SemaRef.ActOnConditionalOp(
+ DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax);
+ if (!MaxUB.isUsable())
+ return nullptr;
+ UBVal = MaxUB.get();
+ } else {
+ // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal),
+ // UB(MaxVal))
+ ExprResult MinUB = SemaRef.ActOnConditionalOp(
+ DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin);
+ if (!MinUB.isUsable())
+ return nullptr;
+ UBVal = MinUB.get();
+ }
+ }
// Upper - Lower
- Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB;
- Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB;
+ Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal;
+ Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal;
Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get();
Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get();
if (!Upper || !Lower)
@@ -5431,12 +6196,142 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations(
return Diff.get();
}
+std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
+ Scope *S, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
+ // Do not build for iterators, they cannot be used in non-rectangular loop
+ // nests.
+ if (LCDecl->getType()->isRecordType())
+ return std::make_pair(nullptr, nullptr);
+ // If we subtract, the min is in the condition, otherwise the min is in the
+ // init value.
+ Expr *MinExpr = nullptr;
+ Expr *MaxExpr = nullptr;
+ Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB;
+ Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB;
+ bool LBNonRect = TestIsLessOp.getValue() ? InitDependOnLC.hasValue()
+ : CondDependOnLC.hasValue();
+ bool UBNonRect = TestIsLessOp.getValue() ? CondDependOnLC.hasValue()
+ : InitDependOnLC.hasValue();
+ Expr *Lower =
+ LBNonRect ? LBExpr : tryBuildCapture(SemaRef, LBExpr, Captures).get();
+ Expr *Upper =
+ UBNonRect ? UBExpr : tryBuildCapture(SemaRef, UBExpr, Captures).get();
+ if (!Upper || !Lower)
+ return std::make_pair(nullptr, nullptr);
+
+ if (TestIsLessOp.getValue())
+ MinExpr = Lower;
+ else
+ MaxExpr = Upper;
+
+ // Build minimum/maximum value based on number of iterations.
+ ExprResult Diff;
+ QualType VarType = LCDecl->getType().getNonReferenceType();
+
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower);
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // Upper - Lower [- 1]
+ if (TestIsStrictOp)
+ Diff = SemaRef.BuildBinOp(
+ S, DefaultLoc, BO_Sub, Diff.get(),
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // Upper - Lower [- 1] + Step
+ ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures);
+ if (!NewStep.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // Parentheses (for dumping/debugging purposes only).
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // (Upper - Lower [- 1]) / Step
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // ((Upper - Lower [- 1]) / Step) * Step
+ // Parentheses (for dumping/debugging purposes only).
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // Convert to the original type or ptrdiff_t, if original type is pointer.
+ if (!VarType->isAnyPointerType() &&
+ !SemaRef.Context.hasSameType(Diff.get()->getType(), VarType)) {
+ Diff = SemaRef.PerformImplicitConversion(
+ Diff.get(), VarType, Sema::AA_Converting, /*AllowExplicit=*/true);
+ } else if (VarType->isAnyPointerType() &&
+ !SemaRef.Context.hasSameType(
+ Diff.get()->getType(),
+ SemaRef.Context.getUnsignedPointerDiffType())) {
+ Diff = SemaRef.PerformImplicitConversion(
+ Diff.get(), SemaRef.Context.getUnsignedPointerDiffType(),
+ Sema::AA_Converting, /*AllowExplicit=*/true);
+ }
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // Parentheses (for dumping/debugging purposes only).
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ if (TestIsLessOp.getValue()) {
+ // MinExpr = Lower;
+ // MaxExpr = Lower + (((Upper - Lower [- 1]) / Step) * Step)
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Lower, Diff.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+ Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false);
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+ MaxExpr = Diff.get();
+ } else {
+ // MaxExpr = Upper;
+ // MinExpr = Upper - (((Upper - Lower [- 1]) / Step) * Step)
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Diff.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+ Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false);
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+ MinExpr = Diff.get();
+ }
+
+ return std::make_pair(MinExpr, MaxExpr);
+}
+
+Expr *OpenMPIterationSpaceChecker::buildFinalCondition(Scope *S) const {
+ if (InitDependOnLC || CondDependOnLC)
+ return Condition;
+ return nullptr;
+}
+
Expr *OpenMPIterationSpaceChecker::buildPreCond(
Scope *S, Expr *Cond,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
+ // Do not build a precondition when the condition/initialization is dependent
+ // to prevent pessimistic early loop exit.
+ // TODO: this can be improved by calculating min/max values but not sure that
+ // it will be very effective.
+ if (CondDependOnLC || InitDependOnLC)
+ return SemaRef.PerformImplicitConversion(
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get(),
+ SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting,
+ /*AllowExplicit=*/true).get();
+
// Try to build LB <op> UB, where <op> is <, >, <=, or >=.
- bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics();
- SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
+ Sema::TentativeAnalysisScope Trap(SemaRef);
ExprResult NewLB = tryBuildCapture(SemaRef, LB, Captures);
ExprResult NewUB = tryBuildCapture(SemaRef, UB, Captures);
@@ -5456,7 +6351,7 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond(
CondExpr.get(), SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting,
/*AllowExplicit=*/true);
}
- SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress);
+
// Otherwise use original loop condition and evaluate it in runtime.
return CondExpr.isUsable() ? CondExpr.get() : Cond;
}
@@ -5561,36 +6456,6 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
return Diff.get();
}
-
-/// Iteration space of a single for loop.
-struct LoopIterationSpace final {
- /// True if the condition operator is the strict compare operator (<, > or
- /// !=).
- bool IsStrictCompare = false;
- /// Condition of the loop.
- Expr *PreCond = nullptr;
- /// This expression calculates the number of iterations in the loop.
- /// It is always possible to calculate it before starting the loop.
- Expr *NumIterations = nullptr;
- /// The loop counter variable.
- Expr *CounterVar = nullptr;
- /// Private loop counter variable.
- Expr *PrivateCounterVar = nullptr;
- /// This is initializer for the initial value of #CounterVar.
- Expr *CounterInit = nullptr;
- /// This is step for the #CounterVar used to generate its update:
- /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration.
- Expr *CounterStep = nullptr;
- /// Should step be subtracted?
- bool Subtract = false;
- /// Source range of the loop init.
- SourceRange InitSrcRange;
- /// Source range of the loop condition.
- SourceRange CondSrcRange;
- /// Source range of the loop increment.
- SourceRange IncSrcRange;
-};
-
} // namespace
void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
@@ -5604,13 +6469,14 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) {
if (ValueDecl *D = ISC.getLoopDecl()) {
auto *VD = dyn_cast<VarDecl>(D);
+ DeclRefExpr *PrivateRef = nullptr;
if (!VD) {
if (VarDecl *Private = isOpenMPCapturedDecl(D)) {
VD = Private;
} else {
- DeclRefExpr *Ref = buildCapture(*this, D, ISC.getLoopDeclRefExpr(),
- /*WithInit=*/false);
- VD = cast<VarDecl>(Ref->getDecl());
+ PrivateRef = buildCapture(*this, D, ISC.getLoopDeclRefExpr(),
+ /*WithInit=*/false);
+ VD = cast<VarDecl>(PrivateRef->getDecl());
}
}
DSAStack->addLoopControlVariable(D, VD);
@@ -5623,6 +6489,51 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
Var->getType().getNonLValueExprType(Context),
ForLoc, /*RefersToCapture=*/true));
}
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables
+ // Referenced in a Construct, C/C++]. The loop iteration variable in the
+ // associated for-loop of a simd construct with just one associated
+ // for-loop may be listed in a linear clause with a constant-linear-step
+ // that is the increment of the associated for-loop. The loop iteration
+ // variable(s) in the associated for-loop(s) of a for or parallel for
+ // construct may be listed in a private or lastprivate clause.
+ DSAStackTy::DSAVarData DVar =
+ DSAStack->getTopDSA(D, /*FromParent=*/false);
+ // If LoopVarRefExpr is nullptr it means the corresponding loop variable
+ // is declared in the loop and it is predetermined as a private.
+ Expr *LoopDeclRefExpr = ISC.getLoopDeclRefExpr();
+ OpenMPClauseKind PredeterminedCKind =
+ isOpenMPSimdDirective(DKind)
+ ? (DSAStack->hasMutipleLoops() ? OMPC_lastprivate : OMPC_linear)
+ : OMPC_private;
+ if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
+ DVar.CKind != PredeterminedCKind && DVar.RefExpr &&
+ (LangOpts.OpenMP <= 45 || (DVar.CKind != OMPC_lastprivate &&
+ DVar.CKind != OMPC_private))) ||
+ ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop ||
+ DKind == OMPD_master_taskloop ||
+ DKind == OMPD_parallel_master_taskloop ||
+ isOpenMPDistributeDirective(DKind)) &&
+ !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
+ DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) &&
+ (DVar.CKind != OMPC_private || DVar.RefExpr)) {
+ Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa)
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPDirectiveName(DKind)
+ << getOpenMPClauseName(PredeterminedCKind);
+ if (DVar.RefExpr == nullptr)
+ DVar.CKind = PredeterminedCKind;
+ reportOriginalDsa(*this, DSAStack, D, DVar,
+ /*IsLoopIterVar=*/true);
+ } else if (LoopDeclRefExpr) {
+ // Make the loop iteration variable private (for worksharing
+ // constructs), linear (for simd directives with the only one
+ // associated loop) or lastprivate (for simd directives with several
+ // collapsed or ordered loops).
+ if (DVar.CKind == OMPC_unknown)
+ DSAStack->addDSA(D, LoopDeclRefExpr, PredeterminedCKind,
+ PrivateRef);
+ }
}
}
DSAStack->setAssociatedLoops(AssociatedLoops - 1);
@@ -5637,12 +6548,15 @@ static bool checkOpenMPIterationSpace(
unsigned TotalNestedLoopCount, Expr *CollapseLoopCountExpr,
Expr *OrderedLoopCountExpr,
Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA,
- LoopIterationSpace &ResultIterSpace,
+ llvm::MutableArrayRef<LoopIterationSpace> ResultIterSpaces,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
- // OpenMP [2.6, Canonical Loop Form]
+ // OpenMP [2.9.1, Canonical Loop Form]
// for (init-expr; test-expr; incr-expr) structured-block
+ // for (range-decl: range-expr) structured-block
auto *For = dyn_cast_or_null<ForStmt>(S);
- if (!For) {
+ auto *CXXFor = dyn_cast_or_null<CXXForRangeStmt>(S);
+ // Ranged for is supported only in OpenMP 5.0.
+ if (!For && (SemaRef.LangOpts.OpenMP <= 45 || !CXXFor)) {
SemaRef.Diag(S->getBeginLoc(), diag::err_omp_not_for)
<< (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr)
<< getOpenMPDirectiveName(DKind) << TotalNestedLoopCount
@@ -5664,12 +6578,14 @@ static bool checkOpenMPIterationSpace(
}
return true;
}
- assert(For->getBody());
+ assert(((For && For->getBody()) || (CXXFor && CXXFor->getBody())) &&
+ "No loop body.");
- OpenMPIterationSpaceChecker ISC(SemaRef, DSA, For->getForLoc());
+ OpenMPIterationSpaceChecker ISC(SemaRef, DSA,
+ For ? For->getForLoc() : CXXFor->getForLoc());
// Check init.
- Stmt *Init = For->getInit();
+ Stmt *Init = For ? For->getInit() : CXXFor->getBeginStmt();
if (ISC.checkAndSetInit(Init))
return true;
@@ -5677,8 +6593,6 @@ static bool checkOpenMPIterationSpace(
// Check loop variable's type.
if (ValueDecl *LCDecl = ISC.getLoopDecl()) {
- Expr *LoopDeclRefExpr = ISC.getLoopDeclRefExpr();
-
// OpenMP [2.6, Canonical Loop Form]
// Var is one of the following:
// A variable of signed or unsigned integer type.
@@ -5704,90 +6618,70 @@ static bool checkOpenMPIterationSpace(
// sharing attributes.
VarsWithImplicitDSA.erase(LCDecl);
- // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
- // in a Construct, C/C++].
- // The loop iteration variable in the associated for-loop of a simd
- // construct with just one associated for-loop may be listed in a linear
- // clause with a constant-linear-step that is the increment of the
- // associated for-loop.
- // The loop iteration variable(s) in the associated for-loop(s) of a for or
- // parallel for construct may be listed in a private or lastprivate clause.
- DSAStackTy::DSAVarData DVar = DSA.getTopDSA(LCDecl, false);
- // If LoopVarRefExpr is nullptr it means the corresponding loop variable is
- // declared in the loop and it is predetermined as a private.
- OpenMPClauseKind PredeterminedCKind =
- isOpenMPSimdDirective(DKind)
- ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate)
- : OMPC_private;
- if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
- DVar.CKind != PredeterminedCKind && DVar.RefExpr &&
- (SemaRef.getLangOpts().OpenMP <= 45 ||
- (DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_private))) ||
- ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop ||
- isOpenMPDistributeDirective(DKind)) &&
- !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
- DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) &&
- (DVar.CKind != OMPC_private || DVar.RefExpr)) {
- SemaRef.Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa)
- << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind)
- << getOpenMPClauseName(PredeterminedCKind);
- if (DVar.RefExpr == nullptr)
- DVar.CKind = PredeterminedCKind;
- reportOriginalDsa(SemaRef, &DSA, LCDecl, DVar, /*IsLoopIterVar=*/true);
- HasErrors = true;
- } else if (LoopDeclRefExpr != nullptr) {
- // Make the loop iteration variable private (for worksharing constructs),
- // linear (for simd directives with the only one associated loop) or
- // lastprivate (for simd directives with several collapsed or ordered
- // loops).
- if (DVar.CKind == OMPC_unknown)
- DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind);
- }
-
assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars");
// Check test-expr.
- HasErrors |= ISC.checkAndSetCond(For->getCond());
+ HasErrors |= ISC.checkAndSetCond(For ? For->getCond() : CXXFor->getCond());
// Check incr-expr.
- HasErrors |= ISC.checkAndSetInc(For->getInc());
+ HasErrors |= ISC.checkAndSetInc(For ? For->getInc() : CXXFor->getInc());
}
if (ISC.dependent() || SemaRef.CurContext->isDependentContext() || HasErrors)
return HasErrors;
// Build the loop's iteration space representation.
- ResultIterSpace.PreCond =
- ISC.buildPreCond(DSA.getCurScope(), For->getCond(), Captures);
- ResultIterSpace.NumIterations = ISC.buildNumIterations(
- DSA.getCurScope(),
- (isOpenMPWorksharingDirective(DKind) ||
- isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)),
- Captures);
- ResultIterSpace.CounterVar = ISC.buildCounterVar(Captures, DSA);
- ResultIterSpace.PrivateCounterVar = ISC.buildPrivateCounterVar();
- ResultIterSpace.CounterInit = ISC.buildCounterInit();
- ResultIterSpace.CounterStep = ISC.buildCounterStep();
- ResultIterSpace.InitSrcRange = ISC.getInitSrcRange();
- ResultIterSpace.CondSrcRange = ISC.getConditionSrcRange();
- ResultIterSpace.IncSrcRange = ISC.getIncrementSrcRange();
- ResultIterSpace.Subtract = ISC.shouldSubtractStep();
- ResultIterSpace.IsStrictCompare = ISC.isStrictTestOp();
-
- HasErrors |= (ResultIterSpace.PreCond == nullptr ||
- ResultIterSpace.NumIterations == nullptr ||
- ResultIterSpace.CounterVar == nullptr ||
- ResultIterSpace.PrivateCounterVar == nullptr ||
- ResultIterSpace.CounterInit == nullptr ||
- ResultIterSpace.CounterStep == nullptr);
+ ResultIterSpaces[CurrentNestedLoopCount].PreCond = ISC.buildPreCond(
+ DSA.getCurScope(), For ? For->getCond() : CXXFor->getCond(), Captures);
+ ResultIterSpaces[CurrentNestedLoopCount].NumIterations =
+ ISC.buildNumIterations(DSA.getCurScope(), ResultIterSpaces,
+ (isOpenMPWorksharingDirective(DKind) ||
+ isOpenMPTaskLoopDirective(DKind) ||
+ isOpenMPDistributeDirective(DKind)),
+ Captures);
+ ResultIterSpaces[CurrentNestedLoopCount].CounterVar =
+ ISC.buildCounterVar(Captures, DSA);
+ ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar =
+ ISC.buildPrivateCounterVar();
+ ResultIterSpaces[CurrentNestedLoopCount].CounterInit = ISC.buildCounterInit();
+ ResultIterSpaces[CurrentNestedLoopCount].CounterStep = ISC.buildCounterStep();
+ ResultIterSpaces[CurrentNestedLoopCount].InitSrcRange = ISC.getInitSrcRange();
+ ResultIterSpaces[CurrentNestedLoopCount].CondSrcRange =
+ ISC.getConditionSrcRange();
+ ResultIterSpaces[CurrentNestedLoopCount].IncSrcRange =
+ ISC.getIncrementSrcRange();
+ ResultIterSpaces[CurrentNestedLoopCount].Subtract = ISC.shouldSubtractStep();
+ ResultIterSpaces[CurrentNestedLoopCount].IsStrictCompare =
+ ISC.isStrictTestOp();
+ std::tie(ResultIterSpaces[CurrentNestedLoopCount].MinValue,
+ ResultIterSpaces[CurrentNestedLoopCount].MaxValue) =
+ ISC.buildMinMaxValues(DSA.getCurScope(), Captures);
+ ResultIterSpaces[CurrentNestedLoopCount].FinalCondition =
+ ISC.buildFinalCondition(DSA.getCurScope());
+ ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularLB =
+ ISC.doesInitDependOnLC();
+ ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularUB =
+ ISC.doesCondDependOnLC();
+ ResultIterSpaces[CurrentNestedLoopCount].LoopDependentIdx =
+ ISC.getLoopDependentIdx();
+
+ HasErrors |=
+ (ResultIterSpaces[CurrentNestedLoopCount].PreCond == nullptr ||
+ ResultIterSpaces[CurrentNestedLoopCount].NumIterations == nullptr ||
+ ResultIterSpaces[CurrentNestedLoopCount].CounterVar == nullptr ||
+ ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar == nullptr ||
+ ResultIterSpaces[CurrentNestedLoopCount].CounterInit == nullptr ||
+ ResultIterSpaces[CurrentNestedLoopCount].CounterStep == nullptr);
if (!HasErrors && DSA.isOrderedRegion()) {
if (DSA.getOrderedRegionParam().second->getNumForLoops()) {
if (CurrentNestedLoopCount <
DSA.getOrderedRegionParam().second->getLoopNumIterations().size()) {
DSA.getOrderedRegionParam().second->setLoopNumIterations(
- CurrentNestedLoopCount, ResultIterSpace.NumIterations);
+ CurrentNestedLoopCount,
+ ResultIterSpaces[CurrentNestedLoopCount].NumIterations);
DSA.getOrderedRegionParam().second->setLoopCounter(
- CurrentNestedLoopCount, ResultIterSpace.CounterVar);
+ CurrentNestedLoopCount,
+ ResultIterSpaces[CurrentNestedLoopCount].CounterVar);
}
}
for (auto &Pair : DSA.getDoacrossDependClauses()) {
@@ -5804,11 +6698,13 @@ static bool checkOpenMPIterationSpace(
Expr *CntValue;
if (Pair.first->getDependencyKind() == OMPC_DEPEND_source)
CntValue = ISC.buildOrderedLoopData(
- DSA.getCurScope(), ResultIterSpace.CounterVar, Captures,
+ DSA.getCurScope(),
+ ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures,
Pair.first->getDependencyLoc());
else
CntValue = ISC.buildOrderedLoopData(
- DSA.getCurScope(), ResultIterSpace.CounterVar, Captures,
+ DSA.getCurScope(),
+ ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures,
Pair.first->getDependencyLoc(),
Pair.second[CurrentNestedLoopCount].first,
Pair.second[CurrentNestedLoopCount].second);
@@ -5822,10 +6718,12 @@ static bool checkOpenMPIterationSpace(
/// Build 'VarRef = Start.
static ExprResult
buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef,
- ExprResult Start,
+ ExprResult Start, bool IsNonRectangularLB,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
// Build 'VarRef = Start.
- ExprResult NewStart = tryBuildCapture(SemaRef, Start.get(), Captures);
+ ExprResult NewStart = IsNonRectangularLB
+ ? Start.get()
+ : tryBuildCapture(SemaRef, Start.get(), Captures);
if (!NewStart.isUsable())
return ExprError();
if (!SemaRef.Context.hasSameType(NewStart.get()->getType(),
@@ -5846,6 +6744,7 @@ buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef,
static ExprResult buildCounterUpdate(
Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef,
ExprResult Start, ExprResult Iter, ExprResult Step, bool Subtract,
+ bool IsNonRectangularLB,
llvm::MapVector<const Expr *, DeclRefExpr *> *Captures = nullptr) {
// Add parentheses (for debugging purposes only).
Iter = SemaRef.ActOnParenExpr(Loc, Loc, Iter.get());
@@ -5865,8 +6764,12 @@ static ExprResult buildCounterUpdate(
// Try to build 'VarRef = Start, VarRef (+|-)= Iter * Step' or
// 'VarRef = Start (+|-) Iter * Step'.
- ExprResult NewStart = Start;
- if (Captures)
+ if (!Start.isUsable())
+ return ExprError();
+ ExprResult NewStart = SemaRef.ActOnParenExpr(Loc, Loc, Start.get());
+ if (!NewStart.isUsable())
+ return ExprError();
+ if (Captures && !IsNonRectangularLB)
NewStart = tryBuildCapture(SemaRef, Start.get(), *Captures);
if (NewStart.isInvalid())
return ExprError();
@@ -5877,8 +6780,8 @@ static ExprResult buildCounterUpdate(
if (VarRef.get()->getType()->isOverloadableType() ||
NewStart.get()->getType()->isOverloadableType() ||
Update.get()->getType()->isOverloadableType()) {
- bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics();
- SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
+ Sema::TentativeAnalysisScope Trap(SemaRef);
+
Update =
SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), NewStart.get());
if (Update.isUsable()) {
@@ -5890,7 +6793,6 @@ static ExprResult buildCounterUpdate(
UpdateVal.get());
}
}
- SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress);
}
// Second attempt: try to build 'VarRef = Start (+|-) Iter * Step'.
@@ -6037,22 +6939,27 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
if (checkOpenMPIterationSpace(
DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount,
std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr,
- OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt],
- Captures))
+ OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures))
return 0;
// Move on to the next nested for loop, or to the loop body.
// OpenMP [2.8.1, simd construct, Restrictions]
// All loops associated with the construct must be perfectly nested; that
// is, there must be no intervening code nor any OpenMP directive between
// any two loops.
- CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers();
+ if (auto *For = dyn_cast<ForStmt>(CurStmt)) {
+ CurStmt = For->getBody();
+ } else {
+ assert(isa<CXXForRangeStmt>(CurStmt) &&
+ "Expected canonical for or range-based for loops.");
+ CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
+ }
+ CurStmt = CurStmt->IgnoreContainers();
}
for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) {
if (checkOpenMPIterationSpace(
DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount,
std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr,
- OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt],
- Captures))
+ OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures))
return 0;
if (Cnt > 0 && IterSpaces[Cnt].CounterVar) {
// Handle initialization of captured loop iterator variables.
@@ -6066,7 +6973,14 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
// All loops associated with the construct must be perfectly nested; that
// is, there must be no intervening code nor any OpenMP directive between
// any two loops.
- CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers();
+ if (auto *For = dyn_cast<ForStmt>(CurStmt)) {
+ CurStmt = For->getBody();
+ } else {
+ assert(isa<CXXForRangeStmt>(CurStmt) &&
+ "Expected canonical for or range-based for loops.");
+ CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
+ }
+ CurStmt = CurStmt->IgnoreContainers();
}
Built.clear(/* size */ NestedLoopCount);
@@ -6513,6 +7427,9 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.Inits.resize(NestedLoopCount);
Built.Updates.resize(NestedLoopCount);
Built.Finals.resize(NestedLoopCount);
+ Built.DependentCounters.resize(NestedLoopCount);
+ Built.DependentInits.resize(NestedLoopCount);
+ Built.FinalsConditions.resize(NestedLoopCount);
{
// We implement the following algorithm for obtaining the
// original loop iteration variable values based on the
@@ -6572,24 +7489,26 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
DeclRefExpr *CounterVar = buildDeclRefExpr(
SemaRef, VD, IS.CounterVar->getType(), IS.CounterVar->getExprLoc(),
/*RefersToCapture=*/true);
- ExprResult Init = buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar,
- IS.CounterInit, Captures);
+ ExprResult Init =
+ buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar,
+ IS.CounterInit, IS.IsNonRectangularLB, Captures);
if (!Init.isUsable()) {
HasErrors = true;
break;
}
ExprResult Update = buildCounterUpdate(
SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Iter,
- IS.CounterStep, IS.Subtract, &Captures);
+ IS.CounterStep, IS.Subtract, IS.IsNonRectangularLB, &Captures);
if (!Update.isUsable()) {
HasErrors = true;
break;
}
// Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step
- ExprResult Final = buildCounterUpdate(
- SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit,
- IS.NumIterations, IS.CounterStep, IS.Subtract, &Captures);
+ ExprResult Final =
+ buildCounterUpdate(SemaRef, CurScope, UpdLoc, CounterVar,
+ IS.CounterInit, IS.NumIterations, IS.CounterStep,
+ IS.Subtract, IS.IsNonRectangularLB, &Captures);
if (!Final.isUsable()) {
HasErrors = true;
break;
@@ -6605,6 +7524,16 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.Inits[Cnt] = Init.get();
Built.Updates[Cnt] = Update.get();
Built.Finals[Cnt] = Final.get();
+ Built.DependentCounters[Cnt] = nullptr;
+ Built.DependentInits[Cnt] = nullptr;
+ Built.FinalsConditions[Cnt] = nullptr;
+ if (IS.IsNonRectangularLB || IS.IsNonRectangularUB) {
+ Built.DependentCounters[Cnt] =
+ Built.Counters[NestedLoopCount - 1 - IS.LoopDependentIdx];
+ Built.DependentInits[Cnt] =
+ Built.Inits[NestedLoopCount - 1 - IS.LoopDependentIdx];
+ Built.FinalsConditions[Cnt] = IS.FinalCondition;
+ }
}
}
@@ -6617,7 +7546,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.NumIterations = NumIterations.get();
Built.CalcLastIteration = SemaRef
.ActOnFinishFullExpr(CalcLastIteration.get(),
- /*DiscardedValue*/ false)
+ /*DiscardedValue=*/false)
.get();
Built.PreCond = PreCond.get();
Built.PreInits = buildPreInits(C, Captures);
@@ -8398,6 +9327,146 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective(
NestedLoopCount, Clauses, AStmt, B);
}
+StmtResult Sema::ActOnOpenMPMasterTaskLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount =
+ checkOpenMPLoop(OMPD_master_taskloop, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkGrainsizeNumTasksClauses(*this, Clauses))
+ return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
+
+ setFunctionHasBranchProtectedScope();
+ return OMPMasterTaskLoopDirective::Create(Context, StartLoc, EndLoc,
+ NestedLoopCount, Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPMasterTaskLoopSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount =
+ checkOpenMPLoop(OMPD_master_taskloop_simd, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ if (!CurContext->isDependentContext()) {
+ // Finalize the clauses that need pre-built expressions for CodeGen.
+ for (OMPClause *C : Clauses) {
+ if (auto *LC = dyn_cast<OMPLinearClause>(C))
+ if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
+ B.NumIterations, *this, CurScope,
+ DSAStack))
+ return StmtError();
+ }
+ }
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkGrainsizeNumTasksClauses(*this, Clauses))
+ return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
+ if (checkSimdlenSafelenSpecified(*this, Clauses))
+ return StmtError();
+
+ setFunctionHasBranchProtectedScope();
+ return OMPMasterTaskLoopSimdDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ auto *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel =
+ getOpenMPCaptureLevels(OMPD_parallel_master_taskloop);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount = checkOpenMPLoop(
+ OMPD_parallel_master_taskloop, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, CS, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkGrainsizeNumTasksClauses(*this, Clauses))
+ return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
+
+ setFunctionHasBranchProtectedScope();
+ return OMPParallelMasterTaskLoopDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
StmtResult Sema::ActOnOpenMPDistributeDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
@@ -9246,6 +10315,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -9287,6 +10358,10 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_exit_data:
CaptureRegion = OMPD_task;
break;
+ case OMPD_parallel_master_taskloop:
+ if (NameModifier == OMPD_unknown || NameModifier == OMPD_taskloop)
+ CaptureRegion = OMPD_parallel;
+ break;
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_sections:
@@ -9302,6 +10377,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
case OMPD_target_data:
// Do not capture if-clause expressions.
break;
@@ -9315,6 +10392,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_teams:
@@ -9358,6 +10436,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_parallel_for_simd:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
+ case OMPD_parallel_master_taskloop:
// Do not capture num_threads-clause expressions.
break;
case OMPD_target_data:
@@ -9373,6 +10452,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
@@ -9383,6 +10464,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_teams:
@@ -9428,6 +10510,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -9452,6 +10537,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -9494,6 +10580,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -9518,6 +10607,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -9560,6 +10650,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -9585,6 +10678,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -9630,6 +10724,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -9651,6 +10748,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -9701,6 +10799,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_sections:
@@ -9716,6 +10817,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -9737,6 +10839,78 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
llvm_unreachable("Unknown OpenMP directive");
}
break;
+ case OMPC_grainsize:
+ case OMPC_num_tasks:
+ case OMPC_final:
+ case OMPC_priority:
+ switch (DKind) {
+ case OMPD_task:
+ case OMPD_taskloop:
+ case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ break;
+ case OMPD_parallel_master_taskloop:
+ CaptureRegion = OMPD_parallel;
+ break;
+ case OMPD_target_update:
+ case OMPD_target_enter_data:
+ case OMPD_target_exit_data:
+ case OMPD_target:
+ case OMPD_target_simd:
+ case OMPD_target_teams:
+ case OMPD_target_parallel:
+ case OMPD_target_teams_distribute:
+ case OMPD_target_teams_distribute_simd:
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd:
+ case OMPD_target_teams_distribute_parallel_for:
+ case OMPD_target_teams_distribute_parallel_for_simd:
+ case OMPD_target_data:
+ case OMPD_teams_distribute_parallel_for:
+ case OMPD_teams_distribute_parallel_for_simd:
+ case OMPD_teams:
+ case OMPD_teams_distribute:
+ case OMPD_teams_distribute_simd:
+ case OMPD_distribute_parallel_for:
+ case OMPD_distribute_parallel_for_simd:
+ case OMPD_cancel:
+ case OMPD_parallel:
+ case OMPD_parallel_sections:
+ case OMPD_parallel_for:
+ case OMPD_parallel_for_simd:
+ case OMPD_threadprivate:
+ case OMPD_allocate:
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ case OMPD_cancellation_point:
+ case OMPD_flush:
+ case OMPD_declare_reduction:
+ case OMPD_declare_mapper:
+ case OMPD_declare_simd:
+ case OMPD_declare_variant:
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
+ case OMPD_simd:
+ case OMPD_for:
+ case OMPD_for_simd:
+ case OMPD_sections:
+ case OMPD_section:
+ case OMPD_single:
+ case OMPD_master:
+ case OMPD_critical:
+ case OMPD_taskgroup:
+ case OMPD_distribute:
+ case OMPD_ordered:
+ case OMPD_atomic:
+ case OMPD_distribute_simd:
+ case OMPD_requires:
+ llvm_unreachable("Unexpected OpenMP directive with grainsize-clause");
+ case OMPD_unknown:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
+ break;
case OMPC_firstprivate:
case OMPC_lastprivate:
case OMPC_reduction:
@@ -9745,7 +10919,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_linear:
case OMPC_default:
case OMPC_proc_bind:
- case OMPC_final:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_allocator:
@@ -9771,10 +10944,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_threads:
case OMPC_simd:
case OMPC_map:
- case OMPC_priority:
- case OMPC_grainsize:
case OMPC_nogroup:
- case OMPC_num_tasks:
case OMPC_hint:
case OMPC_defaultmap:
case OMPC_unknown:
@@ -9788,6 +10958,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Unexpected OpenMP clause.");
}
return CaptureRegion;
@@ -9832,6 +11004,8 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Condition;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
!Condition->isInstantiationDependent() &&
!Condition->containsUnexpandedParameterPack()) {
@@ -9840,10 +11014,21 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition,
return nullptr;
ValExpr = MakeFullExpr(Val.get()).get();
+
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_final);
+ if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
+ ValExpr = MakeFullExpr(ValExpr).get();
+ llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
+ ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
+ HelperValStmt = buildPreInits(Context, Captures);
+ }
}
- return new (Context) OMPFinalClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+ return new (Context) OMPFinalClause(ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, EndLoc);
}
+
ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc,
Expr *Op) {
if (!Op)
@@ -9888,9 +11073,12 @@ ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc,
return PerformContextualImplicitConversion(Loc, Op, ConvertDiagnoser);
}
-static bool isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef,
- OpenMPClauseKind CKind,
- bool StrictlyPositive) {
+static bool
+isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind,
+ bool StrictlyPositive, bool BuildCapture = false,
+ OpenMPDirectiveKind DKind = OMPD_unknown,
+ OpenMPDirectiveKind *CaptureRegion = nullptr,
+ Stmt **HelperValStmt = nullptr) {
if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() &&
!ValExpr->isInstantiationDependent()) {
SourceLocation Loc = ValExpr->getExprLoc();
@@ -9911,6 +11099,16 @@ static bool isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef,
<< ValExpr->getSourceRange();
return false;
}
+ if (!BuildCapture)
+ return true;
+ *CaptureRegion = getOpenMPCaptureRegionForClause(DKind, CKind);
+ if (*CaptureRegion != OMPD_unknown &&
+ !SemaRef.CurContext->isDependentContext()) {
+ ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
+ llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
+ ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
+ *HelperValStmt = buildPreInits(SemaRef.Context, Captures);
+ }
}
return true;
}
@@ -10181,6 +11379,8 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_unified_shared_memory:
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10359,6 +11559,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10568,6 +11770,8 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_use_device_ptr:
case OMPC_is_device_ptr:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10774,6 +11978,8 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10874,7 +12080,13 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
- if (isOpenMPTargetExecutionDirective(CurrDir)) {
+ //
+ // OpenMP 5.0 [2.19.7.1, Restrictions, p.7]
+ // A list item cannot appear in both a map clause and a data-sharing
+ // attribute clause on the same construct unless the construct is a
+ // combined construct.
+ if ((LangOpts.OpenMP <= 45 && isOpenMPTargetExecutionDirective(CurrDir)) ||
+ CurrDir == OMPD_target) {
OpenMPClauseKind ConflictKind;
if (DSAStack->checkMappableExprComponentListsForDecl(
VD, /*CurrentRegionOnly=*/true,
@@ -11109,7 +12321,14 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
- if (isOpenMPTargetExecutionDirective(CurrDir)) {
+ //
+ // OpenMP 5.0 [2.19.7.1, Restrictions, p.7]
+ // A list item cannot appear in both a map clause and a data-sharing
+ // attribute clause on the same construct unless the construct is a
+ // combined construct.
+ if ((LangOpts.OpenMP <= 45 &&
+ isOpenMPTargetExecutionDirective(CurrDir)) ||
+ CurrDir == OMPD_target) {
OpenMPClauseKind ConflictKind;
if (DSAStack->checkMappableExprComponentListsForDecl(
VD, /*CurrentRegionOnly=*/true,
@@ -12133,8 +13352,9 @@ static bool actOnOMPReductionKindClause(
// If we don't have a single element, we must emit a constant array type.
if (ConstantLengthOASE && !SingleElement) {
for (llvm::APSInt &Size : ArraySizes)
- PrivateTy = Context.getConstantArrayType(
- PrivateTy, Size, ArrayType::Normal, /*IndexTypeQuals=*/0);
+ PrivateTy = Context.getConstantArrayType(PrivateTy, Size, nullptr,
+ ArrayType::Normal,
+ /*IndexTypeQuals=*/0);
}
}
@@ -12707,6 +13927,7 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
// Walk the vars and build update/final expressions for the CodeGen.
SmallVector<Expr *, 8> Updates;
SmallVector<Expr *, 8> Finals;
+ SmallVector<Expr *, 8> UsedExprs;
Expr *Step = Clause.getStep();
Expr *CalcStep = Clause.getCalcStep();
// OpenMP [2.14.3.7, linear clause]
@@ -12760,9 +13981,9 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
// Build update: Var = InitExpr + IV * Step
ExprResult Update;
if (!Info.first)
- Update =
- buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate,
- InitExpr, IV, Step, /* Subtract */ false);
+ Update = buildCounterUpdate(
+ SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, InitExpr, IV, Step,
+ /*Subtract=*/false, /*IsNonRectangularLB=*/false);
else
Update = *CurPrivate;
Update = SemaRef.ActOnFinishFullExpr(Update.get(), DE->getBeginLoc(),
@@ -12773,7 +13994,8 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
if (!Info.first)
Final =
buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef,
- InitExpr, NumIterations, Step, /*Subtract=*/false);
+ InitExpr, NumIterations, Step, /*Subtract=*/false,
+ /*IsNonRectangularLB=*/false);
else
Final = *CurPrivate;
Final = SemaRef.ActOnFinishFullExpr(Final.get(), DE->getBeginLoc(),
@@ -12782,16 +14004,24 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
if (!Update.isUsable() || !Final.isUsable()) {
Updates.push_back(nullptr);
Finals.push_back(nullptr);
+ UsedExprs.push_back(nullptr);
HasErrors = true;
} else {
Updates.push_back(Update.get());
Finals.push_back(Final.get());
+ if (!Info.first)
+ UsedExprs.push_back(SimpleRefExpr);
}
++CurInit;
++CurPrivate;
}
+ if (Expr *S = Clause.getStep())
+ UsedExprs.push_back(S);
+ // Fill the remaining part with the nullptr.
+ UsedExprs.append(Clause.varlist_size() + 1 - UsedExprs.size(), nullptr);
Clause.setUpdates(Updates);
Clause.setFinals(Finals);
+ Clause.setUsedExprs(UsedExprs);
return HasErrors;
}
@@ -13216,11 +14446,13 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
<< RefExpr->getSourceRange();
continue;
}
- bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
- getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
- ExprResult Res =
- CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RefExpr->IgnoreParenImpCasts());
- getDiagnostics().setSuppressAllDiagnostics(Suppress);
+
+ ExprResult Res;
+ {
+ Sema::TentativeAnalysisScope Trap(*this);
+ Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf,
+ RefExpr->IgnoreParenImpCasts());
+ }
if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) {
Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
<< RefExpr->getSourceRange();
@@ -13884,6 +15116,11 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
Expr *UnresolvedMapper) {
if (MapperIdScopeSpec.isInvalid())
return ExprError();
+ // Get the actual type for the array type.
+ if (Type->isArrayType()) {
+ assert(Type->getAsArrayTypeUnsafe() && "Expect to get a valid array type");
+ Type = Type->getAsArrayTypeUnsafe()->getElementType().getCanonicalType();
+ }
// Find all user-defined mappers with the given MapperId.
SmallVector<UnresolvedSet<8>, 4> Lookups;
LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName);
@@ -13930,11 +15167,14 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
MapperIdScopeSpec.getWithLocInContext(SemaRef.Context), MapperId,
/*ADL=*/false, /*Overloaded=*/true, URS.begin(), URS.end());
}
+ SourceLocation Loc = MapperId.getLoc();
// [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions
// The type must be of struct, union or class type in C and C++
- if (!Type->isStructureOrClassType() && !Type->isUnionType())
- return ExprEmpty();
- SourceLocation Loc = MapperId.getLoc();
+ if (!Type->isStructureOrClassType() && !Type->isUnionType() &&
+ (MapperIdScopeSpec.isSet() || MapperId.getAsString() != "default")) {
+ SemaRef.Diag(Loc, diag::err_omp_mapper_wrong_type);
+ return ExprError();
+ }
// Perform argument dependent lookup.
if (SemaRef.getLangOpts().CPlusPlus && !MapperIdScopeSpec.isSet())
argumentDependentLookup(SemaRef, MapperId, Loc, Type, Lookups);
@@ -14211,7 +15451,14 @@ static void checkMappableExpressionList(
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
- if (VD && isOpenMPTargetExecutionDirective(DKind)) {
+ //
+ // OpenMP 5.0 [2.19.7.1, Restrictions, p.7]
+ // A list item cannot appear in both a map clause and a data-sharing
+ // attribute clause on the same construct unless the construct is a
+ // combined construct.
+ if (VD && ((SemaRef.LangOpts.OpenMP <= 45 &&
+ isOpenMPTargetExecutionDirective(DKind)) ||
+ DKind == OMPD_target)) {
DSAStackTy::DSAVarData DVar = DSAS->getTopDSA(VD, /*FromParent=*/false);
if (isOpenMPPrivate(DVar.CKind)) {
SemaRef.Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa)
@@ -14745,14 +15992,19 @@ OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Priority;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
// OpenMP [2.9.1, task Constrcut]
// The priority-value is a non-negative numerical scalar expression.
- if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_priority,
- /*StrictlyPositive=*/false))
+ if (!isNonNegativeIntegerValue(
+ ValExpr, *this, OMPC_priority,
+ /*StrictlyPositive=*/false, /*BuildCapture=*/true,
+ DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt))
return nullptr;
- return new (Context) OMPPriorityClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+ return new (Context) OMPPriorityClause(ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize,
@@ -14760,15 +16012,20 @@ OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Grainsize;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
// OpenMP [2.9.2, taskloop Constrcut]
// The parameter of the grainsize clause must be a positive integer
// expression.
- if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_grainsize,
- /*StrictlyPositive=*/true))
+ if (!isNonNegativeIntegerValue(
+ ValExpr, *this, OMPC_grainsize,
+ /*StrictlyPositive=*/true, /*BuildCapture=*/true,
+ DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt))
return nullptr;
- return new (Context) OMPGrainsizeClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+ return new (Context) OMPGrainsizeClause(ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks,
@@ -14776,15 +16033,20 @@ OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = NumTasks;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
// OpenMP [2.9.2, taskloop Constrcut]
// The parameter of the num_tasks clause must be a positive integer
// expression.
- if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_num_tasks,
- /*StrictlyPositive=*/true))
+ if (!isNonNegativeIntegerValue(
+ ValExpr, *this, OMPC_num_tasks,
+ /*StrictlyPositive=*/true, /*BuildCapture=*/true,
+ DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt))
return nullptr;
- return new (Context) OMPNumTasksClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+ return new (Context) OMPNumTasksClause(ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc,
@@ -14905,16 +16167,15 @@ void Sema::ActOnFinishOpenMPDeclareTargetDirective() {
--DeclareTargetNestingLevel;
}
-void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope,
- CXXScopeSpec &ScopeSpec,
- const DeclarationNameInfo &Id,
- OMPDeclareTargetDeclAttr::MapTypeTy MT,
- NamedDeclSetType &SameDirectiveDecls) {
+NamedDecl *
+Sema::lookupOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec,
+ const DeclarationNameInfo &Id,
+ NamedDeclSetType &SameDirectiveDecls) {
LookupResult Lookup(*this, Id, LookupOrdinaryName);
LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
if (Lookup.isAmbiguous())
- return;
+ return nullptr;
Lookup.suppressDiagnostics();
if (!Lookup.isSingleResult()) {
@@ -14925,33 +16186,56 @@ void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope,
diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest)
<< Id.getName());
checkDeclIsAllowedInOpenMPTarget(nullptr, Corrected.getCorrectionDecl());
- return;
+ return nullptr;
}
Diag(Id.getLoc(), diag::err_undeclared_var_use) << Id.getName();
- return;
+ return nullptr;
}
NamedDecl *ND = Lookup.getAsSingle<NamedDecl>();
- if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND) ||
- isa<FunctionTemplateDecl>(ND)) {
- if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl())))
- Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName();
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
- OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
- cast<ValueDecl>(ND));
- if (!Res) {
- auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT);
- ND->addAttr(A);
- if (ASTMutationListener *ML = Context.getASTMutationListener())
- ML->DeclarationMarkedOpenMPDeclareTarget(ND, A);
- checkDeclIsAllowedInOpenMPTarget(nullptr, ND, Id.getLoc());
- } else if (*Res != MT) {
- Diag(Id.getLoc(), diag::err_omp_declare_target_to_and_link)
- << Id.getName();
- }
- } else {
+ if (!isa<VarDecl>(ND) && !isa<FunctionDecl>(ND) &&
+ !isa<FunctionTemplateDecl>(ND)) {
Diag(Id.getLoc(), diag::err_omp_invalid_target_decl) << Id.getName();
+ return nullptr;
+ }
+ if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl())))
+ Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName();
+ return ND;
+}
+
+void Sema::ActOnOpenMPDeclareTargetName(
+ NamedDecl *ND, SourceLocation Loc, OMPDeclareTargetDeclAttr::MapTypeTy MT,
+ OMPDeclareTargetDeclAttr::DevTypeTy DT) {
+ assert((isa<VarDecl>(ND) || isa<FunctionDecl>(ND) ||
+ isa<FunctionTemplateDecl>(ND)) &&
+ "Expected variable, function or function template.");
+
+ // Diagnose marking after use as it may lead to incorrect diagnosis and
+ // codegen.
+ if (LangOpts.OpenMP >= 50 &&
+ (ND->isUsed(/*CheckUsedAttr=*/false) || ND->isReferenced()))
+ Diag(Loc, diag::warn_omp_declare_target_after_first_use);
+
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(cast<ValueDecl>(ND));
+ if (DevTy.hasValue() && *DevTy != DT) {
+ Diag(Loc, diag::err_omp_device_type_mismatch)
+ << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DT)
+ << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(*DevTy);
+ return;
+ }
+ Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
+ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(cast<ValueDecl>(ND));
+ if (!Res) {
+ auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT, DT,
+ SourceRange(Loc, Loc));
+ ND->addAttr(A);
+ if (ASTMutationListener *ML = Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPDeclareTarget(ND, A);
+ checkDeclIsAllowedInOpenMPTarget(nullptr, ND, Loc);
+ } else if (*Res != MT) {
+ Diag(Loc, diag::err_omp_declare_target_to_and_link) << ND;
}
}
@@ -14960,7 +16244,28 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR,
if (!D || !isa<VarDecl>(D))
return;
auto *VD = cast<VarDecl>(D);
- if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
+ Optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy =
+ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
+ if (SemaRef.LangOpts.OpenMP >= 50 &&
+ (SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true) ||
+ SemaRef.getCurBlock() || SemaRef.getCurCapturedRegion()) &&
+ VD->hasGlobalStorage()) {
+ llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy =
+ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
+ if (!MapTy || *MapTy != OMPDeclareTargetDeclAttr::MT_To) {
+ // OpenMP 5.0, 2.12.7 declare target Directive, Restrictions
+ // If a lambda declaration and definition appears between a
+ // declare target directive and the matching end declare target
+ // directive, all variables that are captured by the lambda
+ // expression must also appear in a to clause.
+ SemaRef.Diag(VD->getLocation(),
+ diag::err_omp_lambda_capture_in_declare_target_not_to);
+ SemaRef.Diag(SL, diag::note_var_explicitly_captured_here)
+ << VD << 0 << SR;
+ return;
+ }
+ }
+ if (MapTy.hasValue())
return;
SemaRef.Diag(VD->getLocation(), diag::warn_omp_not_in_target_context);
SemaRef.Diag(SL, diag::note_used_here) << SR;
@@ -14969,7 +16274,7 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR,
static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR,
Sema &SemaRef, DSAStackTy *Stack,
ValueDecl *VD) {
- return VD->hasAttr<OMPDeclareTargetDeclAttr>() ||
+ return OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) ||
checkTypeMappable(SL, SR, SemaRef, Stack, VD->getType(),
/*FullCheck=*/false);
}
@@ -14995,15 +16300,23 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
}
if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
D = FTD->getTemplatedDecl();
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(FD);
- if (Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) {
- assert(IdLoc.isValid() && "Source location is expected");
+ if (IdLoc.isValid() && Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) {
Diag(IdLoc, diag::err_omp_function_in_link_clause);
Diag(FD->getLocation(), diag::note_defined_here) << FD;
return;
}
+ // Mark the function as must be emitted for the device.
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(FD);
+ if (LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() &&
+ *DevTy != OMPDeclareTargetDeclAttr::DT_Host)
+ checkOpenMPDeviceFunction(IdLoc, FD, /*CheckForDelayedContext=*/false);
+ if (!LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() &&
+ *DevTy != OMPDeclareTargetDeclAttr::DT_NoHost)
+ checkOpenMPHostFunction(IdLoc, FD, /*CheckCaller=*/false);
}
if (auto *VD = dyn_cast<ValueDecl>(D)) {
// Problem if any with var declared with incomplete type will be reported
@@ -15016,7 +16329,8 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
if (isa<VarDecl>(D) || isa<FunctionDecl>(D) ||
isa<FunctionTemplateDecl>(D)) {
auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(
- Context, OMPDeclareTargetDeclAttr::MT_To);
+ Context, OMPDeclareTargetDeclAttr::MT_To,
+ OMPDeclareTargetDeclAttr::DT_Any, SourceRange(IdLoc, IdLoc));
D->addAttr(A);
if (ASTMutationListener *ML = Context.getASTMutationListener())
ML->DeclarationMarkedOpenMPDeclareTarget(D, A);
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index f632a4d3bd1a..47c1e3cec0ea 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -257,8 +257,18 @@ isPointerConversionToVoidPointer(ASTContext& Context) const {
/// 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)) {
+static const Expr *IgnoreNarrowingConversion(ASTContext &Ctx,
+ const Expr *Converted) {
+ // We can have cleanups wrapping the converted expression; these need to be
+ // preserved so that destructors run if necessary.
+ if (auto *EWC = dyn_cast<ExprWithCleanups>(Converted)) {
+ Expr *Inner =
+ const_cast<Expr *>(IgnoreNarrowingConversion(Ctx, EWC->getSubExpr()));
+ return ExprWithCleanups::Create(Ctx, Inner, EWC->cleanupsHaveSideEffects(),
+ EWC->getObjects());
+ }
+
+ while (auto *ICE = dyn_cast<ImplicitCastExpr>(Converted)) {
switch (ICE->getCastKind()) {
case CK_NoOp:
case CK_IntegralCast:
@@ -332,7 +342,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
if (IgnoreFloatToIntegralConversion)
return NK_Not_Narrowing;
llvm::APSInt IntConstantValue;
- const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
assert(Initializer && "Unknown conversion expression");
// If it's value-dependent, we can't tell whether it's narrowing.
@@ -370,7 +380,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
if (FromType->isRealFloatingType() && ToType->isRealFloatingType() &&
Ctx.getFloatingTypeOrder(FromType, ToType) == 1) {
// FromType is larger than ToType.
- const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
// If it's value-dependent, we can't tell whether it's narrowing.
if (Initializer->isValueDependent())
@@ -416,7 +426,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind(
(FromSigned && !ToSigned)) {
// Not all values of FromType can be represented in ToType.
llvm::APSInt InitializerValue;
- const Expr *Initializer = IgnoreNarrowingConversion(Converted);
+ const Expr *Initializer = IgnoreNarrowingConversion(Ctx, Converted);
// If it's value-dependent, we can't tell whether it's narrowing.
if (Initializer->isValueDependent())
@@ -838,6 +848,25 @@ llvm::Optional<unsigned> DeductionFailureInfo::getCallArgIndex() {
}
}
+bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
+ OverloadedOperatorKind Op) {
+ if (!AllowRewrittenCandidates)
+ return false;
+ return Op == OO_EqualEqual || Op == OO_Spaceship;
+}
+
+bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(
+ ASTContext &Ctx, const FunctionDecl *FD) {
+ if (!shouldAddReversed(FD->getDeclName().getCXXOverloadedOperator()))
+ return false;
+ // Don't bother adding a reversed candidate that can never be a better
+ // match than the non-reversed version.
+ return FD->getNumParams() != 2 ||
+ !Ctx.hasSameUnqualifiedType(FD->getParamDecl(0)->getType(),
+ FD->getParamDecl(1)->getType()) ||
+ FD->hasAttr<EnableIfAttr>();
+}
+
void OverloadCandidateSet::destroyCandidates() {
for (iterator i = begin(), e = end(); i != e; ++i) {
for (auto &C : i->Conversions)
@@ -1463,14 +1492,14 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
if (TyClass != CanFrom->getTypeClass()) return false;
if (TyClass != Type::FunctionProto && TyClass != Type::FunctionNoProto) {
if (TyClass == Type::Pointer) {
- CanTo = CanTo.getAs<PointerType>()->getPointeeType();
- CanFrom = CanFrom.getAs<PointerType>()->getPointeeType();
+ CanTo = CanTo.castAs<PointerType>()->getPointeeType();
+ CanFrom = CanFrom.castAs<PointerType>()->getPointeeType();
} else if (TyClass == Type::BlockPointer) {
- CanTo = CanTo.getAs<BlockPointerType>()->getPointeeType();
- CanFrom = CanFrom.getAs<BlockPointerType>()->getPointeeType();
+ CanTo = CanTo.castAs<BlockPointerType>()->getPointeeType();
+ CanFrom = CanFrom.castAs<BlockPointerType>()->getPointeeType();
} else if (TyClass == Type::MemberPointer) {
- auto ToMPT = CanTo.getAs<MemberPointerType>();
- auto FromMPT = CanFrom.getAs<MemberPointerType>();
+ auto ToMPT = CanTo.castAs<MemberPointerType>();
+ auto FromMPT = CanFrom.castAs<MemberPointerType>();
// A function pointer conversion cannot change the class of the function.
if (ToMPT->getClass() != FromMPT->getClass())
return false;
@@ -2273,7 +2302,7 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
// Blocks: Block pointers can be converted to void*.
if (FromType->isBlockPointerType() && ToType->isPointerType() &&
- ToType->getAs<PointerType>()->getPointeeType()->isVoidType()) {
+ ToType->castAs<PointerType>()->getPointeeType()->isVoidType()) {
ConvertedType = ToType;
return true;
}
@@ -3272,7 +3301,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
User.ConversionFunction = Constructor;
User.FoundConversionFunction = Best->FoundDecl;
User.After.setAsIdentityConversion();
- User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType());
+ User.After.setFromType(ThisType->castAs<PointerType>()->getPointeeType());
User.After.setAllToTypes(ToType);
return Result;
}
@@ -3463,7 +3492,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
User.ConversionFunction = Constructor;
User.FoundConversionFunction = Best->FoundDecl;
User.After.setAsIdentityConversion();
- User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType());
+ User.After.setFromType(ThisType->castAs<PointerType>()->getPointeeType());
User.After.setAllToTypes(ToType);
return Result;
}
@@ -3755,6 +3784,34 @@ isBetterReferenceBindingKind(const StandardConversionSequence &SCS1,
!SCS2.IsLvalueReference && SCS2.BindsToFunctionLvalue);
}
+enum class FixedEnumPromotion {
+ None,
+ ToUnderlyingType,
+ ToPromotedUnderlyingType
+};
+
+/// Returns kind of fixed enum promotion the \a SCS uses.
+static FixedEnumPromotion
+getFixedEnumPromtion(Sema &S, const StandardConversionSequence &SCS) {
+
+ if (SCS.Second != ICK_Integral_Promotion)
+ return FixedEnumPromotion::None;
+
+ QualType FromType = SCS.getFromType();
+ if (!FromType->isEnumeralType())
+ return FixedEnumPromotion::None;
+
+ EnumDecl *Enum = FromType->getAs<EnumType>()->getDecl();
+ if (!Enum->isFixed())
+ return FixedEnumPromotion::None;
+
+ QualType UnderlyingType = Enum->getIntegerType();
+ if (S.Context.hasSameType(SCS.getToType(1), UnderlyingType))
+ return FixedEnumPromotion::ToUnderlyingType;
+
+ return FixedEnumPromotion::ToPromotedUnderlyingType;
+}
+
/// CompareStandardConversionSequences - Compare two standard
/// conversion sequences to determine whether one is better than the
/// other or if they are indistinguishable (C++ 13.3.3.2p3).
@@ -3796,6 +3853,20 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
? ImplicitConversionSequence::Better
: ImplicitConversionSequence::Worse;
+ // C++14 [over.ics.rank]p4b2:
+ // This is retroactively applied to C++11 by CWG 1601.
+ //
+ // A conversion that promotes an enumeration whose underlying type is fixed
+ // to its underlying type is better than one that promotes to the promoted
+ // underlying type, if the two are different.
+ FixedEnumPromotion FEP1 = getFixedEnumPromtion(S, SCS1);
+ FixedEnumPromotion FEP2 = getFixedEnumPromtion(S, SCS2);
+ if (FEP1 != FixedEnumPromotion::None && FEP2 != FixedEnumPromotion::None &&
+ FEP1 != FEP2)
+ return FEP1 == FixedEnumPromotion::ToUnderlyingType
+ ? ImplicitConversionSequence::Better
+ : ImplicitConversionSequence::Worse;
+
// C++ [over.ics.rank]p4b2:
//
// If class B is derived directly or indirectly from class A,
@@ -4105,14 +4176,14 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
/*FIXME: Remove if Objective-C id conversions get their own rank*/
FromType1->isPointerType() && FromType2->isPointerType() &&
ToType1->isPointerType() && ToType2->isPointerType()) {
- QualType FromPointee1
- = FromType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
- QualType ToPointee1
- = ToType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
- QualType FromPointee2
- = FromType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
- QualType ToPointee2
- = ToType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType();
+ QualType FromPointee1 =
+ FromType1->castAs<PointerType>()->getPointeeType().getUnqualifiedType();
+ QualType ToPointee1 =
+ ToType1->castAs<PointerType>()->getPointeeType().getUnqualifiedType();
+ QualType FromPointee2 =
+ FromType2->castAs<PointerType>()->getPointeeType().getUnqualifiedType();
+ QualType ToPointee2 =
+ ToType2->castAs<PointerType>()->getPointeeType().getUnqualifiedType();
// -- conversion of C* to B* is better than conversion of C* to A*,
if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) {
@@ -4301,7 +4372,8 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
QualType OrigT1, QualType OrigT2,
bool &DerivedToBase,
bool &ObjCConversion,
- bool &ObjCLifetimeConversion) {
+ bool &ObjCLifetimeConversion,
+ bool &FunctionConversion) {
assert(!OrigT1->isReferenceType() &&
"T1 must be the pointee type of the reference type");
assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
@@ -4331,15 +4403,16 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
Context.canBindObjCObjectType(UnqualT1, UnqualT2))
ObjCConversion = true;
else if (UnqualT2->isFunctionType() &&
- IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2))
+ IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) {
// C++1z [dcl.init.ref]p4:
// cv1 T1" is reference-compatible with "cv2 T2" if [...] T2 is "noexcept
// function" and T1 is "function"
//
// We extend this to also apply to 'noreturn', so allow any function
// conversion between function types.
+ FunctionConversion = true;
return Ref_Compatible;
- else
+ } else
return Ref_Incompatible;
// At this point, we know that T1 and T2 are reference-related (at
@@ -4392,7 +4465,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
bool AllowExplicit) {
assert(T2->isRecordType() && "Can only find conversions of record types.");
CXXRecordDecl *T2RecordDecl
- = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
+ = dyn_cast<CXXRecordDecl>(T2->castAs<RecordType>()->getDecl());
OverloadCandidateSet CandidateSet(
DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion);
@@ -4420,6 +4493,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
+ bool FunctionConversion = false;
// If we are initializing an rvalue reference, don't permit conversion
// functions that return lvalues.
@@ -4432,12 +4506,13 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
if (!ConvTemplate &&
S.CompareReferenceRelationship(
- DeclLoc,
- Conv->getConversionType().getNonReferenceType()
- .getUnqualifiedType(),
- DeclType.getNonReferenceType().getUnqualifiedType(),
- DerivedToBase, ObjCConversion, ObjCLifetimeConversion) ==
- Sema::Ref_Incompatible)
+ DeclLoc,
+ Conv->getConversionType()
+ .getNonReferenceType()
+ .getUnqualifiedType(),
+ DeclType.getNonReferenceType().getUnqualifiedType(),
+ DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
+ FunctionConversion) == Sema::Ref_Incompatible)
continue;
} else {
// If the conversion function doesn't return a reference type,
@@ -4523,7 +4598,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
ImplicitConversionSequence ICS;
ICS.setBad(BadConversionSequence::no_conversion, Init, DeclType);
- QualType T1 = DeclType->getAs<ReferenceType>()->getPointeeType();
+ QualType T1 = DeclType->castAs<ReferenceType>()->getPointeeType();
QualType T2 = Init->getType();
// If the initializer is the address of an overloaded function, try
@@ -4541,11 +4616,11 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
bool DerivedToBase = false;
bool ObjCConversion = false;
bool ObjCLifetimeConversion = false;
+ bool FunctionConversion = false;
Expr::Classification InitCategory = Init->Classify(S.Context);
- Sema::ReferenceCompareResult RefRelationship
- = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase,
- ObjCConversion, ObjCLifetimeConversion);
-
+ Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(
+ DeclLoc, T1, T2, DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
+ FunctionConversion);
// C++0x [dcl.init.ref]p5:
// A reference to type "cv1 T1" is initialized by an expression
@@ -4920,13 +4995,11 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
// 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.
- // FIXME: Expose SemaInit's aggregate initialization code so that we don't
- // need to call into the initialization code here; overload resolution
- // should not be doing that.
InitializedEntity Entity =
InitializedEntity::InitializeParameter(S.Context, ToType,
/*Consumed=*/false);
- if (S.CanPerformCopyInitialization(Entity, From)) {
+ if (S.CanPerformAggregateInitializationForOverloadResolution(Entity,
+ From)) {
Result.setUserDefined();
Result.UserDefined.Before.setAsIdentityConversion();
// Initializer lists don't have a type.
@@ -4949,7 +5022,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
// 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();
+ QualType T1 = ToType->castAs<ReferenceType>()->getPointeeType();
// If the initializer list has a single element that is reference-related
// to the parameter type, we initialize the reference from that.
@@ -4972,9 +5045,10 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
bool dummy1 = false;
bool dummy2 = false;
bool dummy3 = false;
+ bool dummy4 = false;
Sema::ReferenceCompareResult RefRelationship =
S.CompareReferenceRelationship(From->getBeginLoc(), T1, T2, dummy1,
- dummy2, dummy3);
+ dummy2, dummy3, dummy4);
if (RefRelationship >= Sema::Ref_Related) {
return TryReferenceInit(S, Init, ToType, /*FIXME*/ From->getBeginLoc(),
@@ -5219,7 +5293,7 @@ Sema::PerformObjectArgumentInitialization(Expr *From,
CXXMethodDecl *Method) {
QualType FromRecordType, DestType;
QualType ImplicitParamRecordType =
- Method->getThisType()->getAs<PointerType>()->getPointeeType();
+ Method->getThisType()->castAs<PointerType>()->getPointeeType();
Expr::Classification FromClassification;
if (const PointerType *PT = From->getType()->getAs<PointerType>()) {
@@ -5467,6 +5541,14 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
if (Result.isInvalid())
return Result;
+ // C++2a [intro.execution]p5:
+ // A full-expression is [...] a constant-expression [...]
+ Result =
+ S.ActOnFinishFullExpr(Result.get(), From->getExprLoc(),
+ /*DiscardedValue=*/false, /*IsConstexpr=*/true);
+ if (Result.isInvalid())
+ return Result;
+
// Check for a narrowing implicit conversion.
APValue PreNarrowingValue;
QualType PreNarrowingType;
@@ -5998,7 +6080,8 @@ void Sema::AddOverloadCandidate(
FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions,
- ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions) {
+ ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions,
+ OverloadCandidateParamOrder PO) {
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
assert(Proto && "Functions without a prototype cannot be overloaded");
@@ -6017,25 +6100,14 @@ void Sema::AddOverloadCandidate(
AddMethodCandidate(Method, FoundDecl, Method->getParent(), QualType(),
Expr::Classification::makeSimpleLValue(), Args,
CandidateSet, SuppressUserConversions,
- PartialOverloading, EarlyConversions);
+ PartialOverloading, EarlyConversions, PO);
return;
}
// We treat a constructor like a non-member function, since its object
// argument doesn't participate in overload resolution.
}
- if (!CandidateSet.isNewCandidate(Function))
- return;
-
- // C++ [over.match.oper]p3:
- // if no operand has a class type, only those non-member functions in the
- // lookup set that have a first parameter of type T1 or "reference to
- // (possibly cv-qualified) T1", when T1 is an enumeration type, or (if there
- // is a right operand) a second parameter of type T2 or "reference to
- // (possibly cv-qualified) T2", when T2 is an enumeration type, are
- // candidate functions.
- if (CandidateSet.getKind() == OverloadCandidateSet::CSK_Operator &&
- !IsAcceptableNonMemberOperatorCandidate(Context, Function, Args))
+ if (!CandidateSet.isNewCandidate(Function, PO))
return;
// C++11 [class.copy]p11: [DR1402]
@@ -6050,12 +6122,25 @@ void Sema::AddOverloadCandidate(
EnterExpressionEvaluationContext Unevaluated(
*this, Sema::ExpressionEvaluationContext::Unevaluated);
+ // C++ [over.match.oper]p3:
+ // if no operand has a class type, only those non-member functions in the
+ // lookup set that have a first parameter of type T1 or "reference to
+ // (possibly cv-qualified) T1", when T1 is an enumeration type, or (if there
+ // is a right operand) a second parameter of type T2 or "reference to
+ // (possibly cv-qualified) T2", when T2 is an enumeration type, are
+ // candidate functions.
+ if (CandidateSet.getKind() == OverloadCandidateSet::CSK_Operator &&
+ !IsAcceptableNonMemberOperatorCandidate(Context, Function, Args))
+ return;
+
// Add this candidate
OverloadCandidate &Candidate =
CandidateSet.addCandidate(Args.size(), EarlyConversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Function;
Candidate.Viable = true;
+ Candidate.RewriteKind =
+ CandidateSet.getRewriteInfo().getRewriteKind(Function, PO);
Candidate.IsSurrogate = false;
Candidate.IsADLCandidate = IsADLCandidate;
Candidate.IgnoreObjectArgument = false;
@@ -6155,7 +6240,9 @@ void Sema::AddOverloadCandidate(
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
- if (Candidate.Conversions[ArgIdx].isInitialized()) {
+ unsigned ConvIdx =
+ PO == OverloadCandidateParamOrder::Reversed ? 1 - ArgIdx : ArgIdx;
+ if (Candidate.Conversions[ConvIdx].isInitialized()) {
// We already formed a conversion sequence for this parameter during
// template argument deduction.
} else if (ArgIdx < NumParams) {
@@ -6164,12 +6251,12 @@ void Sema::AddOverloadCandidate(
// (13.3.3.1) that converts that argument to the corresponding
// parameter of F.
QualType ParamType = Proto->getParamType(ArgIdx);
- Candidate.Conversions[ArgIdx] = TryCopyInitialization(
+ Candidate.Conversions[ConvIdx] = TryCopyInitialization(
*this, Args[ArgIdx], ParamType, SuppressUserConversions,
/*InOverloadResolution=*/true,
/*AllowObjCWritebackConversion=*/
getLangOpts().ObjCAutoRefCount, AllowExplicitConversions);
- if (Candidate.Conversions[ArgIdx].isBad()) {
+ if (Candidate.Conversions[ConvIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
@@ -6178,7 +6265,7 @@ void Sema::AddOverloadCandidate(
// (C++ 13.3.2p2): For the purposes of overload resolution, any
// argument for which there is no corresponding parameter is
// considered to ""match the ellipsis" (C+ 13.3.3.1.3).
- Candidate.Conversions[ArgIdx].setEllipsis();
+ Candidate.Conversions[ConvIdx].setEllipsis();
}
}
@@ -6525,9 +6612,10 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
FunctionArgs = Args.slice(1);
}
if (FunTmpl) {
- AddTemplateOverloadCandidate(
- FunTmpl, F.getPair(), ExplicitTemplateArgs, FunctionArgs,
- CandidateSet, SuppressUserConversions, PartialOverloading);
+ AddTemplateOverloadCandidate(FunTmpl, F.getPair(),
+ ExplicitTemplateArgs, FunctionArgs,
+ CandidateSet, SuppressUserConversions,
+ PartialOverloading);
} else {
AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet,
SuppressUserConversions, PartialOverloading);
@@ -6538,12 +6626,12 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
/// AddMethodCandidate - Adds a named decl (which is some kind of
/// method) as a method candidate to the given overload set.
-void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
- QualType ObjectType,
+void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType,
Expr::Classification ObjectClassification,
ArrayRef<Expr *> Args,
- OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions) {
+ OverloadCandidateSet &CandidateSet,
+ bool SuppressUserConversions,
+ OverloadCandidateParamOrder PO) {
NamedDecl *Decl = FoundDecl.getDecl();
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(Decl->getDeclContext());
@@ -6556,11 +6644,11 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl,
AddMethodTemplateCandidate(TD, FoundDecl, ActingContext,
/*ExplicitArgs*/ nullptr, ObjectType,
ObjectClassification, Args, CandidateSet,
- SuppressUserConversions);
+ SuppressUserConversions, false, PO);
} else {
AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext,
ObjectType, ObjectClassification, Args, CandidateSet,
- SuppressUserConversions);
+ SuppressUserConversions, false, None, PO);
}
}
@@ -6579,14 +6667,15 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions,
bool PartialOverloading,
- ConversionSequenceList EarlyConversions) {
+ ConversionSequenceList EarlyConversions,
+ OverloadCandidateParamOrder PO) {
const FunctionProtoType *Proto
= dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
assert(Proto && "Methods without a prototype cannot be overloaded");
assert(!isa<CXXConstructorDecl>(Method) &&
"Use AddOverloadCandidate for constructors");
- if (!CandidateSet.isNewCandidate(Method))
+ if (!CandidateSet.isNewCandidate(Method, PO))
return;
// C++11 [class.copy]p23: [DR1402]
@@ -6605,6 +6694,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CandidateSet.addCandidate(Args.size() + 1, EarlyConversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = Method;
+ Candidate.RewriteKind =
+ CandidateSet.getRewriteInfo().getRewriteKind(Method, PO);
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument = false;
Candidate.ExplicitCallArguments = Args.size();
@@ -6640,12 +6731,13 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// The implicit object argument is ignored.
Candidate.IgnoreObjectArgument = true;
else {
+ unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0;
// Determine the implicit conversion sequence for the object
// parameter.
- Candidate.Conversions[0] = TryObjectArgumentInitialization(
+ Candidate.Conversions[ConvIdx] = TryObjectArgumentInitialization(
*this, CandidateSet.getLocation(), ObjectType, ObjectClassification,
Method, ActingContext);
- if (Candidate.Conversions[0].isBad()) {
+ if (Candidate.Conversions[ConvIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
@@ -6664,7 +6756,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// Determine the implicit conversion sequences for each of the
// arguments.
for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) {
- if (Candidate.Conversions[ArgIdx + 1].isInitialized()) {
+ unsigned ConvIdx =
+ PO == OverloadCandidateParamOrder::Reversed ? 0 : (ArgIdx + 1);
+ if (Candidate.Conversions[ConvIdx].isInitialized()) {
// We already formed a conversion sequence for this parameter during
// template argument deduction.
} else if (ArgIdx < NumParams) {
@@ -6673,13 +6767,13 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// (13.3.3.1) that converts that argument to the corresponding
// parameter of F.
QualType ParamType = Proto->getParamType(ArgIdx);
- Candidate.Conversions[ArgIdx + 1]
+ Candidate.Conversions[ConvIdx]
= TryCopyInitialization(*this, Args[ArgIdx], ParamType,
SuppressUserConversions,
/*InOverloadResolution=*/true,
/*AllowObjCWritebackConversion=*/
getLangOpts().ObjCAutoRefCount);
- if (Candidate.Conversions[ArgIdx + 1].isBad()) {
+ if (Candidate.Conversions[ConvIdx].isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
return;
@@ -6688,7 +6782,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
// (C++ 13.3.2p2): For the purposes of overload resolution, any
// argument for which there is no corresponding parameter is
// considered to "match the ellipsis" (C+ 13.3.3.1.3).
- Candidate.Conversions[ArgIdx + 1].setEllipsis();
+ Candidate.Conversions[ConvIdx].setEllipsis();
}
}
@@ -6709,18 +6803,14 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
/// Add a C++ member function template as a candidate to the candidate
/// set, using template argument deduction to produce an appropriate member
/// function template specialization.
-void
-Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
- DeclAccessPair FoundDecl,
- CXXRecordDecl *ActingContext,
- TemplateArgumentListInfo *ExplicitTemplateArgs,
- QualType ObjectType,
- Expr::Classification ObjectClassification,
- ArrayRef<Expr *> Args,
- OverloadCandidateSet& CandidateSet,
- bool SuppressUserConversions,
- bool PartialOverloading) {
- if (!CandidateSet.isNewCandidate(MethodTmpl))
+void Sema::AddMethodTemplateCandidate(
+ FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl,
+ CXXRecordDecl *ActingContext,
+ TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType,
+ Expr::Classification ObjectClassification, ArrayRef<Expr *> Args,
+ OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
+ bool PartialOverloading, OverloadCandidateParamOrder PO) {
+ if (!CandidateSet.isNewCandidate(MethodTmpl, PO))
return;
// C++ [over.match.funcs]p7:
@@ -6741,13 +6831,15 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
return CheckNonDependentConversions(
MethodTmpl, ParamTypes, Args, CandidateSet, Conversions,
SuppressUserConversions, ActingContext, ObjectType,
- ObjectClassification);
+ ObjectClassification, PO);
})) {
OverloadCandidate &Candidate =
CandidateSet.addCandidate(Conversions.size(), Conversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = MethodTmpl->getTemplatedDecl();
Candidate.Viable = false;
+ Candidate.RewriteKind =
+ CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO);
Candidate.IsSurrogate = false;
Candidate.IgnoreObjectArgument =
cast<CXXMethodDecl>(Candidate.Function)->isStatic() ||
@@ -6771,7 +6863,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl,
ActingContext, ObjectType, ObjectClassification, Args,
CandidateSet, SuppressUserConversions, PartialOverloading,
- Conversions);
+ Conversions, PO);
}
/// Add a C++ function template specialization as a candidate
@@ -6781,8 +6873,9 @@ void Sema::AddTemplateOverloadCandidate(
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
- bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate) {
- if (!CandidateSet.isNewCandidate(FunctionTemplate))
+ bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate,
+ OverloadCandidateParamOrder PO) {
+ if (!CandidateSet.isNewCandidate(FunctionTemplate, PO))
return;
// C++ [over.match.funcs]p7:
@@ -6800,15 +6893,17 @@ void Sema::AddTemplateOverloadCandidate(
if (TemplateDeductionResult Result = DeduceTemplateArguments(
FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info,
PartialOverloading, [&](ArrayRef<QualType> ParamTypes) {
- return CheckNonDependentConversions(FunctionTemplate, ParamTypes,
- Args, CandidateSet, Conversions,
- SuppressUserConversions);
+ return CheckNonDependentConversions(
+ FunctionTemplate, ParamTypes, Args, CandidateSet, Conversions,
+ SuppressUserConversions, nullptr, QualType(), {}, PO);
})) {
OverloadCandidate &Candidate =
CandidateSet.addCandidate(Conversions.size(), Conversions);
Candidate.FoundDecl = FoundDecl;
Candidate.Function = FunctionTemplate->getTemplatedDecl();
Candidate.Viable = false;
+ Candidate.RewriteKind =
+ CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO);
Candidate.IsSurrogate = false;
Candidate.IsADLCandidate = IsADLCandidate;
// Ignore the object argument if there is one, since we don't have an object
@@ -6833,7 +6928,7 @@ void Sema::AddTemplateOverloadCandidate(
AddOverloadCandidate(
Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions,
PartialOverloading, AllowExplicit,
- /*AllowExplicitConversions*/ false, IsADLCandidate, Conversions);
+ /*AllowExplicitConversions*/ false, IsADLCandidate, Conversions, PO);
}
/// Check that implicit conversion sequences can be formed for each argument
@@ -6844,7 +6939,7 @@ bool Sema::CheckNonDependentConversions(
ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet,
ConversionSequenceList &Conversions, bool SuppressUserConversions,
CXXRecordDecl *ActingContext, QualType ObjectType,
- Expr::Classification ObjectClassification) {
+ Expr::Classification ObjectClassification, OverloadCandidateParamOrder PO) {
// FIXME: The cases in which we allow explicit conversions for constructor
// arguments never consider calling a constructor template. It's not clear
// that is correct.
@@ -6867,10 +6962,11 @@ bool Sema::CheckNonDependentConversions(
// overload resolution is permitted to sidestep instantiations.
if (HasThisConversion && !cast<CXXMethodDecl>(FD)->isStatic() &&
!ObjectType.isNull()) {
- Conversions[0] = TryObjectArgumentInitialization(
+ unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0;
+ Conversions[ConvIdx] = TryObjectArgumentInitialization(
*this, CandidateSet.getLocation(), ObjectType, ObjectClassification,
Method, ActingContext);
- if (Conversions[0].isBad())
+ if (Conversions[ConvIdx].isBad())
return true;
}
@@ -6878,14 +6974,17 @@ bool Sema::CheckNonDependentConversions(
++I) {
QualType ParamType = ParamTypes[I];
if (!ParamType->isDependentType()) {
- Conversions[ThisConversions + I]
+ unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed
+ ? 0
+ : (ThisConversions + I);
+ Conversions[ConvIdx]
= TryCopyInitialization(*this, Args[I], ParamType,
SuppressUserConversions,
/*InOverloadResolution=*/true,
/*AllowObjCWritebackConversion=*/
getLangOpts().ObjCAutoRefCount,
AllowExplicit);
- if (Conversions[ThisConversions + I].isBad())
+ if (Conversions[ConvIdx].isBad())
return true;
}
}
@@ -6998,7 +7097,7 @@ void Sema::AddConversionCandidate(
if (const PointerType *FromPtrType = ImplicitParamType->getAs<PointerType>())
ImplicitParamType = FromPtrType->getPointeeType();
CXXRecordDecl *ConversionContext
- = cast<CXXRecordDecl>(ImplicitParamType->getAs<RecordType>()->getDecl());
+ = cast<CXXRecordDecl>(ImplicitParamType->castAs<RecordType>()->getDecl());
Candidate.Conversions[0] = TryObjectArgumentInitialization(
*this, CandidateSet.getLocation(), From->getType(),
@@ -7052,10 +7151,9 @@ void Sema::AddConversionCandidate(
// allocator).
QualType CallResultType = ConversionType.getNonLValueExprType(Context);
- llvm::AlignedCharArray<alignof(CallExpr), sizeof(CallExpr) + sizeof(Stmt *)>
- Buffer;
+ alignas(CallExpr) char Buffer[sizeof(CallExpr) + sizeof(Stmt *)];
CallExpr *TheTemporaryCall = CallExpr::CreateTemporary(
- Buffer.buffer, &ConversionFn, CallResultType, VK, From->getBeginLoc());
+ Buffer, &ConversionFn, CallResultType, VK, From->getBeginLoc());
ImplicitConversionSequence ICS =
TryCopyInitialization(*this, TheTemporaryCall, ToType,
@@ -7274,6 +7372,48 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
}
}
+/// Add all of the non-member operator function declarations in the given
+/// function set to the overload candidate set.
+void Sema::AddNonMemberOperatorCandidates(
+ const UnresolvedSetImpl &Fns, ArrayRef<Expr *> Args,
+ OverloadCandidateSet &CandidateSet,
+ TemplateArgumentListInfo *ExplicitTemplateArgs) {
+ for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) {
+ NamedDecl *D = F.getDecl()->getUnderlyingDecl();
+ ArrayRef<Expr *> FunctionArgs = Args;
+
+ FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D);
+ FunctionDecl *FD =
+ FunTmpl ? FunTmpl->getTemplatedDecl() : cast<FunctionDecl>(D);
+
+ // Don't consider rewritten functions if we're not rewriting.
+ if (!CandidateSet.getRewriteInfo().isAcceptableCandidate(FD))
+ continue;
+
+ assert(!isa<CXXMethodDecl>(FD) &&
+ "unqualified operator lookup found a member function");
+
+ if (FunTmpl) {
+ AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs,
+ FunctionArgs, CandidateSet);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD))
+ AddTemplateOverloadCandidate(
+ FunTmpl, F.getPair(), ExplicitTemplateArgs,
+ {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, false, false,
+ true, ADLCallKind::NotADL, OverloadCandidateParamOrder::Reversed);
+ } else {
+ if (ExplicitTemplateArgs)
+ continue;
+ AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD))
+ AddOverloadCandidate(FD, F.getPair(),
+ {FunctionArgs[1], FunctionArgs[0]}, CandidateSet,
+ false, false, true, false, ADLCallKind::NotADL,
+ None, OverloadCandidateParamOrder::Reversed);
+ }
+ }
+}
+
/// Add overload candidates for overloaded operators that are
/// member functions.
///
@@ -7285,8 +7425,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
SourceLocation OpLoc,
ArrayRef<Expr *> Args,
- OverloadCandidateSet& CandidateSet,
- SourceRange OpRange) {
+ OverloadCandidateSet &CandidateSet,
+ OverloadCandidateParamOrder PO) {
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
// C++ [over.match.oper]p3:
@@ -7321,7 +7461,7 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
++Oper)
AddMethodCandidate(Oper.getPair(), Args[0]->getType(),
Args[0]->Classify(Context), Args.slice(1),
- CandidateSet, /*SuppressUserConversion=*/false);
+ CandidateSet, /*SuppressUserConversion=*/false, PO);
}
}
@@ -7776,7 +7916,7 @@ class BuiltinOperatorOverloadBuilder {
static constexpr int ArithmeticTypesCap = 24;
SmallVector<CanQualType, ArithmeticTypesCap> ArithmeticTypes;
- // Define some indices used to iterate over the arithemetic types in
+ // Define some indices used to iterate over the arithmetic types in
// ArithmeticTypes. The "promoted arithmetic types" are the arithmetic
// types are that preserved by promotion (C++ [over.built]p2).
unsigned FirstIntegralType,
@@ -8126,10 +8266,16 @@ public:
if (C->Function->isFunctionTemplateSpecialization())
continue;
- QualType FirstParamType =
- C->Function->getParamDecl(0)->getType().getUnqualifiedType();
- QualType SecondParamType =
- C->Function->getParamDecl(1)->getType().getUnqualifiedType();
+ // We interpret "same parameter-type-list" as applying to the
+ // "synthesized candidate, with the order of the two parameters
+ // reversed", not to the original function.
+ bool Reversed = C->RewriteKind & CRK_Reversed;
+ QualType FirstParamType = C->Function->getParamDecl(Reversed ? 1 : 0)
+ ->getType()
+ .getUnqualifiedType();
+ QualType SecondParamType = C->Function->getParamDecl(Reversed ? 0 : 1)
+ ->getType()
+ .getUnqualifiedType();
// Skip if either parameter isn't of enumeral type.
if (!FirstParamType->isEnumeralType() ||
@@ -8759,7 +8905,7 @@ public:
Enum = CandidateTypes[ArgIdx].enumeration_begin(),
EnumEnd = CandidateTypes[ArgIdx].enumeration_end();
Enum != EnumEnd; ++Enum) {
- if (!(*Enum)->getAs<EnumType>()->getDecl()->isScoped())
+ if (!(*Enum)->castAs<EnumType>()->getDecl()->isScoped())
continue;
if (!AddedTypes.insert(S.Context.getCanonicalType(*Enum)).second)
@@ -9183,6 +9329,7 @@ bool clang::isBetterOverloadCandidate(
// 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...
+ bool HasWorseConversion = false;
for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) {
switch (CompareImplicitConversionSequences(S, Loc,
Cand1.Conversions[ArgIdx],
@@ -9193,6 +9340,24 @@ bool clang::isBetterOverloadCandidate(
break;
case ImplicitConversionSequence::Worse:
+ if (Cand1.Function && Cand1.Function == Cand2.Function &&
+ (Cand2.RewriteKind & CRK_Reversed) != 0) {
+ // Work around large-scale breakage caused by considering reversed
+ // forms of operator== in C++20:
+ //
+ // When comparing a function against its reversed form, if we have a
+ // better conversion for one argument and a worse conversion for the
+ // other, we prefer the non-reversed form.
+ //
+ // This prevents a conversion function from being considered ambiguous
+ // with its own reversed form in various where it's only incidentally
+ // heterogeneous.
+ //
+ // We diagnose this as an extension from CreateOverloadedBinOp.
+ HasWorseConversion = true;
+ break;
+ }
+
// Cand1 can't be better than Cand2.
return false;
@@ -9206,6 +9371,8 @@ bool clang::isBetterOverloadCandidate(
// ICSj(F2), or, if not that,
if (HasBetterConversion)
return true;
+ if (HasWorseConversion)
+ return false;
// -- the context is an initialization by user-defined conversion
// (see 8.5, 13.3.1.5) and the standard conversion sequence
@@ -9273,8 +9440,10 @@ bool clang::isBetterOverloadCandidate(
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
}
- // FIXME: Work around a defect in the C++17 inheriting constructor wording.
- // A derived-class constructor beats an (inherited) base class constructor.
+ // -- F1 is a constructor for a class D, F2 is a constructor for a base
+ // class B of D, and for all arguments the corresponding parameters of
+ // F1 and F2 have the same type.
+ // FIXME: Implement the "all parameters have the same type" check.
bool Cand1IsInherited =
dyn_cast_or_null<ConstructorUsingShadowDecl>(Cand1.FoundDecl.getDecl());
bool Cand2IsInherited =
@@ -9292,6 +9461,16 @@ bool clang::isBetterOverloadCandidate(
// Inherited from sibling base classes: still ambiguous.
}
+ // -- F2 is a rewritten candidate (12.4.1.2) and F1 is not
+ // -- F1 and F2 are rewritten candidates, and F2 is a synthesized candidate
+ // with reversed order of parameters and F1 is not
+ //
+ // We rank reversed + different operator as worse than just reversed, but
+ // that comparison can never happen, because we only consider reversing for
+ // the maximally-rewritten operator (== or <=>).
+ if (Cand1.RewriteKind != Cand2.RewriteKind)
+ return Cand1.RewriteKind < Cand2.RewriteKind;
+
// Check C++17 tie-breakers for deduction guides.
{
auto *Guide1 = dyn_cast_or_null<CXXDeductionGuideDecl>(Cand1.Function);
@@ -9425,13 +9604,15 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
const FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext);
bool ContainsSameSideCandidate =
llvm::any_of(Candidates, [&](OverloadCandidate *Cand) {
- return Cand->Function &&
+ // Check viable function only.
+ return Cand->Viable && Cand->Function &&
S.IdentifyCUDAPreference(Caller, Cand->Function) ==
Sema::CFP_SameSide;
});
if (ContainsSameSideCandidate) {
auto IsWrongSideCandidate = [&](OverloadCandidate *Cand) {
- return Cand->Function &&
+ // Check viable function only to avoid unnecessary data copying/moving.
+ return Cand->Viable && Cand->Function &&
S.IdentifyCUDAPreference(Caller, Cand->Function) ==
Sema::CFP_WrongSide;
};
@@ -9485,6 +9666,7 @@ namespace {
enum OverloadCandidateKind {
oc_function,
oc_method,
+ oc_reversed_binary_operator,
oc_constructor,
oc_implicit_default_constructor,
oc_implicit_copy_constructor,
@@ -9502,6 +9684,7 @@ enum OverloadCandidateSelect {
static std::pair<OverloadCandidateKind, OverloadCandidateSelect>
ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn,
+ OverloadCandidateRewriteKind CRK,
std::string &Description) {
bool isTemplate = Fn->isTemplateDecl() || Found->isTemplateDecl();
@@ -9518,6 +9701,9 @@ ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn,
}();
OverloadCandidateKind Kind = [&]() {
+ if (CRK & CRK_Reversed)
+ return oc_reversed_binary_operator;
+
if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) {
if (!Ctor->isImplicit()) {
if (isa<ConstructorUsingShadowDecl>(Found))
@@ -9642,6 +9828,7 @@ bool Sema::checkAddressOfFunctionIsAvailable(const FunctionDecl *Function,
// Notes the location of an overload candidate.
void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn,
+ OverloadCandidateRewriteKind RewriteKind,
QualType DestType, bool TakingAddress) {
if (TakingAddress && !checkAddressOfCandidateIsAvailable(*this, Fn))
return;
@@ -9651,7 +9838,7 @@ void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn,
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> KSPair =
- ClassifyOverloadCandidate(*this, Found, Fn, FnDesc);
+ ClassifyOverloadCandidate(*this, Found, Fn, RewriteKind, FnDesc);
PartialDiagnostic PD = PDiag(diag::note_ovl_candidate)
<< (unsigned)KSPair.first << (unsigned)KSPair.second
<< Fn << FnDesc;
@@ -9675,11 +9862,11 @@ void Sema::NoteAllOverloadCandidates(Expr *OverloadedExpr, QualType DestType,
I != IEnd; ++I) {
if (FunctionTemplateDecl *FunTmpl =
dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()) ) {
- NoteOverloadCandidate(*I, FunTmpl->getTemplatedDecl(), DestType,
+ NoteOverloadCandidate(*I, FunTmpl->getTemplatedDecl(), CRK_None, DestType,
TakingAddress);
} else if (FunctionDecl *Fun
= dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()) ) {
- NoteOverloadCandidate(*I, Fun, DestType, TakingAddress);
+ NoteOverloadCandidate(*I, Fun, CRK_None, DestType, TakingAddress);
}
}
}
@@ -9729,7 +9916,8 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
- ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc);
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->RewriteKind,
+ FnDesc);
Expr *FromExpr = Conv.Bad.FromExpr;
QualType FromTy = Conv.Bad.getFromType();
@@ -10001,7 +10189,7 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D,
std::string Description;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
- ClassifyOverloadCandidate(S, Found, Fn, Description);
+ ClassifyOverloadCandidate(S, Found, Fn, CRK_None, Description);
if (modeCount == 1 && Fn->getParamDecl(0)->getDeclName())
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity_one)
@@ -10298,7 +10486,8 @@ static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
- ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee, FnDesc);
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee, Cand->RewriteKind,
+ FnDesc);
S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target)
<< (unsigned)FnKindPair.first << (unsigned)ocs_non_template
@@ -10416,7 +10605,8 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
if (Fn->isDeleted()) {
std::string FnDesc;
std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair =
- ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc);
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->RewriteKind,
+ FnDesc);
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)
<< (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc
@@ -10426,7 +10616,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
}
// We don't really have anything else to say about viable candidates.
- S.NoteOverloadCandidate(Cand->FoundDecl, Fn);
+ S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind);
return;
}
@@ -10459,7 +10649,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_trivial_conversion:
case ovl_fail_bad_final_conversion:
case ovl_fail_final_conversion_not_exact:
- return S.NoteOverloadCandidate(Cand->FoundDecl, Fn);
+ return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind);
case ovl_fail_bad_conversion: {
unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0);
@@ -10470,7 +10660,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
// FIXME: this currently happens when we're called from SemaInit
// when user-conversion overload fails. Figure out how to handle
// those conditions and diagnose them well.
- return S.NoteOverloadCandidate(Cand->FoundDecl, Fn);
+ return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind);
}
case ovl_fail_bad_target:
@@ -10550,12 +10740,12 @@ static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc,
TypeStr += Cand->BuiltinParamTypes[0].getAsString();
if (Cand->Conversions.size() == 1) {
TypeStr += ")";
- S.Diag(OpLoc, diag::note_ovl_builtin_unary_candidate) << TypeStr;
+ S.Diag(OpLoc, diag::note_ovl_builtin_candidate) << TypeStr;
} else {
TypeStr += ", ";
TypeStr += Cand->BuiltinParamTypes[1].getAsString();
TypeStr += ")";
- S.Diag(OpLoc, diag::note_ovl_builtin_binary_candidate) << TypeStr;
+ S.Diag(OpLoc, diag::note_ovl_builtin_candidate) << TypeStr;
}
}
@@ -10746,8 +10936,10 @@ struct CompareOverloadCandidatesForDisplay {
/// CompleteNonViableCandidate - Normally, overload resolution only
/// computes up to the first bad conversion. Produces the FixIt set if
/// possible.
-static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
- ArrayRef<Expr *> Args) {
+static void
+CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
+ ArrayRef<Expr *> Args,
+ OverloadCandidateSet::CandidateSetKind CSK) {
assert(!Cand->Viable);
// Don't do anything on failures other than bad conversion.
@@ -10775,6 +10967,7 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
bool SuppressUserConversions = false;
unsigned ConvIdx = 0;
+ unsigned ArgIdx = 0;
ArrayRef<QualType> ParamTypes;
if (Cand->IsSurrogate) {
@@ -10782,16 +10975,19 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
= Cand->Surrogate->getConversionType().getNonReferenceType();
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
ConvType = ConvPtrType->getPointeeType();
- ParamTypes = ConvType->getAs<FunctionProtoType>()->getParamTypes();
- // Conversion 0 is 'this', which doesn't have a corresponding argument.
+ ParamTypes = ConvType->castAs<FunctionProtoType>()->getParamTypes();
+ // Conversion 0 is 'this', which doesn't have a corresponding parameter.
ConvIdx = 1;
} else if (Cand->Function) {
ParamTypes =
- Cand->Function->getType()->getAs<FunctionProtoType>()->getParamTypes();
+ Cand->Function->getType()->castAs<FunctionProtoType>()->getParamTypes();
if (isa<CXXMethodDecl>(Cand->Function) &&
!isa<CXXConstructorDecl>(Cand->Function)) {
- // Conversion 0 is 'this', which doesn't have a corresponding argument.
+ // Conversion 0 is 'this', which doesn't have a corresponding parameter.
ConvIdx = 1;
+ if (CSK == OverloadCandidateSet::CSK_Operator)
+ // Argument 0 is 'this', which doesn't have a corresponding parameter.
+ ArgIdx = 1;
}
} else {
// Builtin operator.
@@ -10800,16 +10996,19 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
}
// Fill in the rest of the conversions.
- for (unsigned ArgIdx = 0; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) {
+ bool Reversed = Cand->RewriteKind & CRK_Reversed;
+ for (unsigned ParamIdx = Reversed ? ParamTypes.size() - 1 : 0;
+ ConvIdx != ConvCount;
+ ++ConvIdx, ++ArgIdx, ParamIdx += (Reversed ? -1 : 1)) {
if (Cand->Conversions[ConvIdx].isInitialized()) {
// We've already checked this conversion.
} else if (ArgIdx < ParamTypes.size()) {
- if (ParamTypes[ArgIdx]->isDependentType())
+ if (ParamTypes[ParamIdx]->isDependentType())
Cand->Conversions[ConvIdx].setAsIdentityConversion(
Args[ArgIdx]->getType());
else {
Cand->Conversions[ConvIdx] =
- TryCopyInitialization(S, Args[ArgIdx], ParamTypes[ArgIdx],
+ TryCopyInitialization(S, Args[ArgIdx], ParamTypes[ParamIdx],
SuppressUserConversions,
/*InOverloadResolution=*/true,
/*AllowObjCWritebackConversion=*/
@@ -10837,7 +11036,7 @@ SmallVector<OverloadCandidate *, 32> OverloadCandidateSet::CompleteCandidates(
if (Cand->Viable)
Cands.push_back(Cand);
else if (OCD == OCD_AllCandidates) {
- CompleteNonViableCandidate(S, Cand, Args);
+ CompleteNonViableCandidate(S, Cand, Args, Kind);
if (Cand->Function || Cand->IsSurrogate)
Cands.push_back(Cand);
// Otherwise, this a non-viable builtin candidate. We do not, in general,
@@ -11394,7 +11593,7 @@ public:
if (FunctionDecl *Fun =
dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()))
if (!functionHasPassObjectSizeParams(Fun))
- S.NoteOverloadCandidate(*I, Fun, TargetFunctionType,
+ S.NoteOverloadCandidate(*I, Fun, CRK_None, TargetFunctionType,
/*TakingAddress=*/true);
FailedCandidates.NoteCandidates(S, OvlExpr->getBeginLoc());
}
@@ -12344,7 +12543,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);
// Add the candidates from the given function set.
- AddFunctionCandidates(Fns, ArgsArray, CandidateSet);
+ AddNonMemberOperatorCandidates(Fns, ArgsArray, CandidateSet);
// Add operator candidates that are member functions.
AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
@@ -12489,14 +12688,17 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
///
/// \param LHS Left-hand argument.
/// \param RHS Right-hand argument.
-ExprResult
-Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
- BinaryOperatorKind Opc,
- const UnresolvedSetImpl &Fns,
- Expr *LHS, Expr *RHS, bool PerformADL) {
+ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
+ BinaryOperatorKind Opc,
+ const UnresolvedSetImpl &Fns, Expr *LHS,
+ Expr *RHS, bool PerformADL,
+ bool AllowRewrittenCandidates) {
Expr *Args[2] = { LHS, RHS };
LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple
+ if (!getLangOpts().CPlusPlus2a)
+ AllowRewrittenCandidates = false;
+
OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc);
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
@@ -12554,23 +12756,61 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// Build an empty overload set.
- OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);
+ OverloadCandidateSet CandidateSet(
+ OpLoc, OverloadCandidateSet::CSK_Operator,
+ OverloadCandidateSet::OperatorRewriteInfo(Op, AllowRewrittenCandidates));
- // Add the candidates from the given function set.
- AddFunctionCandidates(Fns, Args, CandidateSet);
+ OverloadedOperatorKind ExtraOp =
+ AllowRewrittenCandidates ? getRewrittenOverloadedOperator(Op) : OO_None;
+
+ // Add the candidates from the given function set. This also adds the
+ // rewritten candidates using these functions if necessary.
+ AddNonMemberOperatorCandidates(Fns, Args, CandidateSet);
// Add operator candidates that are member functions.
AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(Op))
+ AddMemberOperatorCandidates(Op, OpLoc, {Args[1], Args[0]}, CandidateSet,
+ OverloadCandidateParamOrder::Reversed);
+
+ // In C++20, also add any rewritten member candidates.
+ if (ExtraOp) {
+ AddMemberOperatorCandidates(ExtraOp, OpLoc, Args, CandidateSet);
+ if (CandidateSet.getRewriteInfo().shouldAddReversed(ExtraOp))
+ AddMemberOperatorCandidates(ExtraOp, OpLoc, {Args[1], Args[0]},
+ CandidateSet,
+ OverloadCandidateParamOrder::Reversed);
+ }
// Add candidates from ADL. Per [over.match.oper]p2, this lookup is not
// performed for an assignment operator (nor for operator[] nor operator->,
// which don't get here).
- if (Opc != BO_Assign && PerformADL)
+ if (Opc != BO_Assign && PerformADL) {
AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
/*ExplicitTemplateArgs*/ nullptr,
CandidateSet);
+ if (ExtraOp) {
+ DeclarationName ExtraOpName =
+ Context.DeclarationNames.getCXXOperatorName(ExtraOp);
+ AddArgumentDependentLookupCandidates(ExtraOpName, OpLoc, Args,
+ /*ExplicitTemplateArgs*/ nullptr,
+ CandidateSet);
+ }
+ }
// Add builtin operator candidates.
+ //
+ // FIXME: We don't add any rewritten candidates here. This is strictly
+ // incorrect; a builtin candidate could be hidden by a non-viable candidate,
+ // resulting in our selecting a rewritten builtin candidate. For example:
+ //
+ // enum class E { e };
+ // bool operator!=(E, E) requires false;
+ // bool k = E::e != E::e;
+ //
+ // ... should select the rewritten builtin candidate 'operator==(E, E)'. But
+ // it seems unreasonable to consider rewritten builtin candidates. A core
+ // issue has been filed proposing to removed this requirement.
AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
@@ -12582,11 +12822,57 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// We found a built-in operator or an overloaded operator.
FunctionDecl *FnDecl = Best->Function;
+ bool IsReversed = (Best->RewriteKind & CRK_Reversed);
+ if (IsReversed)
+ std::swap(Args[0], Args[1]);
+
if (FnDecl) {
Expr *Base = nullptr;
// We matched an overloaded operator. Build a call to that
// operator.
+ OverloadedOperatorKind ChosenOp =
+ FnDecl->getDeclName().getCXXOverloadedOperator();
+
+ // C++2a [over.match.oper]p9:
+ // If a rewritten operator== candidate is selected by overload
+ // resolution for an operator@, its return type shall be cv bool
+ if (Best->RewriteKind && ChosenOp == OO_EqualEqual &&
+ !FnDecl->getReturnType()->isBooleanType()) {
+ Diag(OpLoc, diag::err_ovl_rewrite_equalequal_not_bool)
+ << FnDecl->getReturnType() << BinaryOperator::getOpcodeStr(Opc)
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ Diag(FnDecl->getLocation(), diag::note_declared_at);
+ return ExprError();
+ }
+
+ if (AllowRewrittenCandidates && !IsReversed &&
+ CandidateSet.getRewriteInfo().shouldAddReversed(ChosenOp)) {
+ // We could have reversed this operator, but didn't. Check if the
+ // reversed form was a viable candidate, and if so, if it had a
+ // better conversion for either parameter. If so, this call is
+ // formally ambiguous, and allowing it is an extension.
+ for (OverloadCandidate &Cand : CandidateSet) {
+ if (Cand.Viable && Cand.Function == FnDecl &&
+ Cand.RewriteKind & CRK_Reversed) {
+ for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) {
+ if (CompareImplicitConversionSequences(
+ *this, OpLoc, Cand.Conversions[ArgIdx],
+ Best->Conversions[ArgIdx]) ==
+ ImplicitConversionSequence::Better) {
+ Diag(OpLoc, diag::ext_ovl_ambiguous_oper_binary_reversed)
+ << BinaryOperator::getOpcodeStr(Opc)
+ << Args[0]->getType() << Args[1]->getType()
+ << Args[0]->getSourceRange() << Args[1]->getSourceRange();
+ Diag(FnDecl->getLocation(),
+ diag::note_ovl_ambiguous_oper_binary_reversed_candidate);
+ }
+ }
+ break;
+ }
+ }
+ }
+
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
// Best->Access is only meaningful for class members.
@@ -12640,8 +12926,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
ResultTy = ResultTy.getNonLValueExprType(Context);
CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
- Context, Op, FnExpr.get(), Args, ResultTy, VK, OpLoc, FPFeatures,
- Best->IsADLCandidate);
+ Context, ChosenOp, FnExpr.get(), Args, ResultTy, VK, OpLoc,
+ FPFeatures, Best->IsADLCandidate);
if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall,
FnDecl))
@@ -12663,7 +12949,46 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
isa<CXXMethodDecl>(FnDecl), OpLoc, TheCall->getSourceRange(),
VariadicDoesNotApply);
- return MaybeBindToTemporary(TheCall);
+ ExprResult R = MaybeBindToTemporary(TheCall);
+ if (R.isInvalid())
+ return ExprError();
+
+ // For a rewritten candidate, we've already reversed the arguments
+ // if needed. Perform the rest of the rewrite now.
+ if ((Best->RewriteKind & CRK_DifferentOperator) ||
+ (Op == OO_Spaceship && IsReversed)) {
+ if (Op == OO_ExclaimEqual) {
+ assert(ChosenOp == OO_EqualEqual && "unexpected operator name");
+ R = CreateBuiltinUnaryOp(OpLoc, UO_LNot, R.get());
+ } else {
+ assert(ChosenOp == OO_Spaceship && "unexpected operator name");
+ llvm::APSInt Zero(Context.getTypeSize(Context.IntTy), false);
+ Expr *ZeroLiteral =
+ IntegerLiteral::Create(Context, Zero, Context.IntTy, OpLoc);
+
+ Sema::CodeSynthesisContext Ctx;
+ Ctx.Kind = Sema::CodeSynthesisContext::RewritingOperatorAsSpaceship;
+ Ctx.Entity = FnDecl;
+ pushCodeSynthesisContext(Ctx);
+
+ R = CreateOverloadedBinOp(
+ OpLoc, Opc, Fns, IsReversed ? ZeroLiteral : R.get(),
+ IsReversed ? R.get() : ZeroLiteral, PerformADL,
+ /*AllowRewrittenCandidates=*/false);
+
+ popCodeSynthesisContext();
+ }
+ if (R.isInvalid())
+ return ExprError();
+ } else {
+ assert(ChosenOp == Op && "unexpected operator name");
+ }
+
+ // Make a note in the AST if we did any rewriting.
+ if (Best->RewriteKind != CRK_None)
+ R = new (Context) CXXRewrittenBinaryOperator(R.get(), IsReversed);
+
+ return R;
} else {
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
@@ -12753,10 +13078,12 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return ExprError();
}
CandidateSet.NoteCandidates(
- PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_deleted_oper)
- << BinaryOperator::getOpcodeStr(Opc)
- << Args[0]->getSourceRange()
- << Args[1]->getSourceRange()),
+ PartialDiagnosticAt(
+ OpLoc, PDiag(diag::err_ovl_deleted_oper)
+ << getOperatorSpelling(Best->Function->getDeclName()
+ .getCXXOverloadedOperator())
+ << Args[0]->getSourceRange()
+ << Args[1]->getSourceRange()),
*this, OCD_AllCandidates, Args, BinaryOperator::getOpcodeStr(Opc),
OpLoc);
return ExprError();
@@ -13633,8 +13960,8 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
OverloadCandidateSet CandidateSet(UDSuffixLoc,
OverloadCandidateSet::CSK_Normal);
- AddFunctionCandidates(R.asUnresolvedSet(), Args, CandidateSet, TemplateArgs,
- /*SuppressUserConversions=*/true);
+ AddNonMemberOperatorCandidates(R.asUnresolvedSet(), Args, CandidateSet,
+ TemplateArgs);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 480155df8990..6c680f29da4f 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -196,6 +196,25 @@ static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) {
return true;
}
+static bool DiagnoseNoDiscard(Sema &S, const WarnUnusedResultAttr *A,
+ SourceLocation Loc, SourceRange R1,
+ SourceRange R2, bool IsCtor) {
+ if (!A)
+ return false;
+ StringRef Msg = A->getMessage();
+
+ if (Msg.empty()) {
+ if (IsCtor)
+ return S.Diag(Loc, diag::warn_unused_constructor) << A << R1 << R2;
+ return S.Diag(Loc, diag::warn_unused_result) << A << R1 << R2;
+ }
+
+ if (IsCtor)
+ return S.Diag(Loc, diag::warn_unused_constructor_msg) << A << Msg << R1
+ << R2;
+ return S.Diag(Loc, diag::warn_unused_result_msg) << A << Msg << R1 << R2;
+}
+
void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
if (const LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S))
return DiagnoseUnusedExprResult(Label->getSubStmt());
@@ -254,14 +273,19 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
return;
E = WarnExpr;
+ if (const auto *Cast = dyn_cast<CastExpr>(E))
+ if (Cast->getCastKind() == CK_NoOp ||
+ Cast->getCastKind() == CK_ConstructorConversion)
+ E = Cast->getSubExpr()->IgnoreImpCasts();
+
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
if (E->getType()->isVoidType())
return;
- if (const Attr *A = CE->getUnusedResultAttr(Context)) {
- Diag(Loc, diag::warn_unused_result) << A << R1 << R2;
+ if (DiagnoseNoDiscard(*this, cast_or_null<WarnUnusedResultAttr>(
+ CE->getUnusedResultAttr(Context)),
+ Loc, R1, R2, /*isCtor=*/false))
return;
- }
// If the callee has attribute pure, const, or warn_unused_result, warn with
// a more specific message to make it clear what is happening. If the call
@@ -279,9 +303,24 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
return;
}
}
+ } else if (const auto *CE = dyn_cast<CXXConstructExpr>(E)) {
+ if (const CXXConstructorDecl *Ctor = CE->getConstructor()) {
+ const auto *A = Ctor->getAttr<WarnUnusedResultAttr>();
+ A = A ? A : Ctor->getParent()->getAttr<WarnUnusedResultAttr>();
+ if (DiagnoseNoDiscard(*this, A, Loc, R1, R2, /*isCtor=*/true))
+ return;
+ }
+ } else if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
+ if (const TagDecl *TD = ILE->getType()->getAsTagDecl()) {
+
+ if (DiagnoseNoDiscard(*this, TD->getAttr<WarnUnusedResultAttr>(), Loc, R1,
+ R2, /*isCtor=*/false))
+ return;
+ }
} else if (ShouldSuppress)
return;
+ E = WarnExpr;
if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
if (getLangOpts().ObjCAutoRefCount && ME->isDelegateInitCall()) {
Diag(Loc, diag::err_arc_unused_init_message) << R1;
@@ -289,10 +328,9 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
}
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (MD) {
- if (const auto *A = MD->getAttr<WarnUnusedResultAttr>()) {
- Diag(Loc, diag::warn_unused_result) << A << R1 << R2;
+ if (DiagnoseNoDiscard(*this, MD->getAttr<WarnUnusedResultAttr>(), Loc, R1,
+ R2, /*isCtor=*/false))
return;
- }
}
} else if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
const Expr *Source = POE->getSyntacticForm();
@@ -392,45 +430,44 @@ Sema::ActOnCaseExpr(SourceLocation CaseLoc, ExprResult Val) {
// If we're not inside a switch, let the 'case' statement handling diagnose
// this. Just clean up after the expression as best we can.
- if (!getCurFunction()->SwitchStack.empty()) {
- Expr *CondExpr =
- getCurFunction()->SwitchStack.back().getPointer()->getCond();
- if (!CondExpr)
- return ExprError();
- QualType CondType = CondExpr->getType();
-
- auto CheckAndFinish = [&](Expr *E) {
- if (CondType->isDependentType() || E->isTypeDependent())
- return ExprResult(E);
-
- if (getLangOpts().CPlusPlus11) {
- // C++11 [stmt.switch]p2: the constant-expression shall be a converted
- // constant expression of the promoted type of the switch condition.
- llvm::APSInt TempVal;
- return CheckConvertedConstantExpression(E, CondType, TempVal,
- CCEK_CaseValue);
- }
+ if (getCurFunction()->SwitchStack.empty())
+ return ActOnFinishFullExpr(Val.get(), Val.get()->getExprLoc(), false,
+ getLangOpts().CPlusPlus11);
- ExprResult ER = E;
- if (!E->isValueDependent())
- ER = VerifyIntegerConstantExpression(E);
- if (!ER.isInvalid())
- ER = DefaultLvalueConversion(ER.get());
- if (!ER.isInvalid())
- ER = ImpCastExprToType(ER.get(), CondType, CK_IntegralCast);
- return ER;
- };
+ Expr *CondExpr =
+ getCurFunction()->SwitchStack.back().getPointer()->getCond();
+ if (!CondExpr)
+ return ExprError();
+ QualType CondType = CondExpr->getType();
- ExprResult Converted = CorrectDelayedTyposInExpr(Val, CheckAndFinish);
- if (Converted.get() == Val.get())
- Converted = CheckAndFinish(Val.get());
- if (Converted.isInvalid())
- return ExprError();
- Val = Converted;
- }
+ auto CheckAndFinish = [&](Expr *E) {
+ if (CondType->isDependentType() || E->isTypeDependent())
+ return ExprResult(E);
+
+ if (getLangOpts().CPlusPlus11) {
+ // C++11 [stmt.switch]p2: the constant-expression shall be a converted
+ // constant expression of the promoted type of the switch condition.
+ llvm::APSInt TempVal;
+ return CheckConvertedConstantExpression(E, CondType, TempVal,
+ CCEK_CaseValue);
+ }
- return ActOnFinishFullExpr(Val.get(), Val.get()->getExprLoc(), false,
- getLangOpts().CPlusPlus11);
+ ExprResult ER = E;
+ if (!E->isValueDependent())
+ ER = VerifyIntegerConstantExpression(E);
+ if (!ER.isInvalid())
+ ER = DefaultLvalueConversion(ER.get());
+ if (!ER.isInvalid())
+ ER = ImpCastExprToType(ER.get(), CondType, CK_IntegralCast);
+ if (!ER.isInvalid())
+ ER = ActOnFinishFullExpr(ER.get(), ER.get()->getExprLoc(), false);
+ return ER;
+ };
+
+ ExprResult Converted = CorrectDelayedTyposInExpr(Val, CheckAndFinish);
+ if (Converted.get() == Val.get())
+ Converted = CheckAndFinish(Val.get());
+ return Converted;
}
StmtResult
@@ -926,7 +963,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// condition is constant.
llvm::APSInt ConstantCondValue;
bool HasConstantCond = false;
- if (!HasDependentValue && !TheDefaultStmt) {
+ if (!TheDefaultStmt) {
Expr::EvalResult Result;
HasConstantCond = CondExpr->EvaluateAsInt(Result, Context,
Expr::SE_AllowSideEffects);
@@ -2637,6 +2674,11 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc,
if (Kind == BFRK_Check)
return StmtResult();
+ // In OpenMP loop region loop control variable must be private. Perform
+ // analysis of first part (if any).
+ if (getLangOpts().OpenMP >= 50 && BeginDeclStmt.isUsable())
+ ActOnOpenMPLoopInitialization(ForLoc, BeginDeclStmt.get());
+
return new (Context) CXXForRangeStmt(
InitStmt, RangeDS, cast_or_null<DeclStmt>(BeginDeclStmt.get()),
cast_or_null<DeclStmt>(EndDeclStmt.get()), NotEqExpr.get(),
@@ -3268,18 +3310,18 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
assert(!FnRetType.isNull());
- if (BlockScopeInfo *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) {
- if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) {
+ if (auto *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) {
+ if (CurBlock->FunctionType->castAs<FunctionType>()->getNoReturnAttr()) {
Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr);
return StmtError();
}
- } else if (CapturedRegionScopeInfo *CurRegion =
- dyn_cast<CapturedRegionScopeInfo>(CurCap)) {
+ } else if (auto *CurRegion = dyn_cast<CapturedRegionScopeInfo>(CurCap)) {
Diag(ReturnLoc, diag::err_return_in_captured_stmt) << CurRegion->getRegionName();
return StmtError();
} else {
assert(CurLambda && "unknown kind of captured scope");
- if (CurLambda->CallOperator->getType()->getAs<FunctionType>()
+ if (CurLambda->CallOperator->getType()
+ ->castAs<FunctionType>()
->getNoReturnAttr()) {
Diag(ReturnLoc, diag::err_noreturn_lambda_has_return_expr);
return StmtError();
@@ -3463,6 +3505,14 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
return true;
}
+ // CUDA: Kernel function must have 'void' return type.
+ if (getLangOpts().CUDA)
+ if (FD->hasAttr<CUDAGlobalAttr>() && !Deduced->isVoidType()) {
+ Diag(FD->getLocation(), diag::err_kern_type_not_void_return)
+ << FD->getType() << FD->getSourceRange();
+ return true;
+ }
+
// If a function with a declared return type that contains a placeholder type
// has multiple return statements, the return type is deduced for each return
// statement. [...] if the type deduced is not the same in each deduction,
@@ -4296,7 +4346,8 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
CapturedRegionKind Kind,
- ArrayRef<CapturedParamNameType> Params) {
+ ArrayRef<CapturedParamNameType> Params,
+ unsigned OpenMPCaptureLevel) {
CapturedDecl *CD = nullptr;
RecordDecl *RD = CreateCapturedStmtRecordDecl(CD, Loc, Params.size());
@@ -4341,7 +4392,7 @@ void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
CD->setContextParam(ParamNum, Param);
}
// Enter the capturing scope for this captured region.
- PushCapturedRegionScope(CurScope, CD, RD, Kind);
+ PushCapturedRegionScope(CurScope, CD, RD, Kind, OpenMPCaptureLevel);
if (CurScope)
PushDeclContext(CurScope, CD);
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index b123a739a7ab..9b051e02d127 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -383,25 +383,19 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
} else if (Info.requiresImmediateConstant() && !Info.allowsRegister()) {
if (!InputExpr->isValueDependent()) {
Expr::EvalResult EVResult;
- if (!InputExpr->EvaluateAsRValue(EVResult, Context, true))
- return StmtError(
- Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected)
- << Info.getConstraintStr() << InputExpr->getSourceRange());
-
- // For compatibility with GCC, we also allow pointers that would be
- // integral constant expressions if they were cast to int.
- llvm::APSInt IntResult;
- if (!EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(),
- Context))
- return StmtError(
- Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected)
- << Info.getConstraintStr() << InputExpr->getSourceRange());
-
- if (!Info.isValidAsmImmediate(IntResult))
- return StmtError(Diag(InputExpr->getBeginLoc(),
- diag::err_invalid_asm_value_for_constraint)
- << IntResult.toString(10) << Info.getConstraintStr()
- << InputExpr->getSourceRange());
+ if (InputExpr->EvaluateAsRValue(EVResult, Context, true)) {
+ // For compatibility with GCC, we also allow pointers that would be
+ // integral constant expressions if they were cast to int.
+ llvm::APSInt IntResult;
+ if (EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(),
+ Context))
+ if (!Info.isValidAsmImmediate(IntResult))
+ return StmtError(Diag(InputExpr->getBeginLoc(),
+ diag::err_invalid_asm_value_for_constraint)
+ << IntResult.toString(10)
+ << Info.getConstraintStr()
+ << InputExpr->getSourceRange());
+ }
}
} else {
diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp
index 791c52c2d913..3d91893b4065 100644
--- a/lib/Sema/SemaStmtAttr.cpp
+++ b/lib/Sema/SemaStmtAttr.cpp
@@ -23,8 +23,7 @@ using namespace sema;
static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const ParsedAttr &A,
SourceRange Range) {
- FallThroughAttr Attr(A.getRange(), S.Context,
- A.getAttributeSpellingListIndex());
+ FallThroughAttr Attr(S.Context, A);
if (!isa<NullStmt>(St)) {
S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target)
<< Attr.getSpelling() << St->getBeginLoc();
@@ -45,10 +44,10 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const ParsedAttr &A,
// about using it as an extension.
if (!S.getLangOpts().CPlusPlus17 && A.isCXX11Attribute() &&
!A.getScopeName())
- S.Diag(A.getLoc(), diag::ext_cxx17_attr) << A.getName();
+ S.Diag(A.getLoc(), diag::ext_cxx17_attr) << A;
FnScope->setHasFallthroughStmt();
- return ::new (S.Context) auto(Attr);
+ return ::new (S.Context) FallThroughAttr(S.Context, A);
}
static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A,
@@ -71,8 +70,7 @@ static Attr *handleSuppressAttr(Sema &S, Stmt *St, const ParsedAttr &A,
}
return ::new (S.Context) SuppressAttr(
- A.getRange(), S.Context, DiagnosticIdentifiers.data(),
- DiagnosticIdentifiers.size(), A.getAttributeSpellingListIndex());
+ S.Context, A, DiagnosticIdentifiers.data(), DiagnosticIdentifiers.size());
}
static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
@@ -97,8 +95,6 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
return nullptr;
}
- LoopHintAttr::Spelling Spelling =
- LoopHintAttr::Spelling(A.getAttributeSpellingListIndex());
LoopHintAttr::OptionType Option;
LoopHintAttr::LoopHintState State;
@@ -133,6 +129,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
.Case("vectorize", LoopHintAttr::Vectorize)
.Case("vectorize_width", LoopHintAttr::VectorizeWidth)
.Case("interleave", LoopHintAttr::Interleave)
+ .Case("vectorize_predicate", LoopHintAttr::VectorizePredicate)
.Case("interleave_count", LoopHintAttr::InterleaveCount)
.Case("unroll", LoopHintAttr::Unroll)
.Case("unroll_count", LoopHintAttr::UnrollCount)
@@ -151,6 +148,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
State = LoopHintAttr::Numeric;
} else if (Option == LoopHintAttr::Vectorize ||
Option == LoopHintAttr::Interleave ||
+ Option == LoopHintAttr::VectorizePredicate ||
Option == LoopHintAttr::Unroll ||
Option == LoopHintAttr::Distribute ||
Option == LoopHintAttr::PipelineDisabled) {
@@ -169,8 +167,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
llvm_unreachable("bad loop hint");
}
- return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, State,
- ValueExpr, A.getRange());
+ return LoopHintAttr::CreateImplicit(S.Context, Option, State, ValueExpr, A);
}
static void
@@ -189,7 +186,8 @@ CheckForIncompatibleAttributes(Sema &S,
const LoopHintAttr *StateAttr;
const LoopHintAttr *NumericAttr;
} HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr},
- {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}};
+ {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr},
+ {nullptr, nullptr}};
for (const auto *I : Attrs) {
const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
@@ -205,7 +203,8 @@ CheckForIncompatibleAttributes(Sema &S,
Unroll,
UnrollAndJam,
Distribute,
- Pipeline
+ Pipeline,
+ VectorizePredicate
} Category;
switch (Option) {
case LoopHintAttr::Vectorize:
@@ -232,6 +231,9 @@ CheckForIncompatibleAttributes(Sema &S,
case LoopHintAttr::PipelineInitiationInterval:
Category = Pipeline;
break;
+ case LoopHintAttr::VectorizePredicate:
+ Category = VectorizePredicate;
+ break;
};
assert(Category < sizeof(HintAttrs) / sizeof(HintAttrs[0]));
@@ -240,6 +242,7 @@ CheckForIncompatibleAttributes(Sema &S,
if (Option == LoopHintAttr::Vectorize ||
Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll ||
Option == LoopHintAttr::UnrollAndJam ||
+ Option == LoopHintAttr::VectorizePredicate ||
Option == LoopHintAttr::PipelineDisabled ||
Option == LoopHintAttr::Distribute) {
// Enable|Disable|AssumeSafety hint. For example, vectorize(enable).
@@ -322,7 +325,7 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
S.Diag(A.getLoc(), A.isDeclspecAttribute()
? (unsigned)diag::warn_unhandled_ms_attribute_ignored
: (unsigned)diag::warn_unknown_attribute_ignored)
- << A.getName();
+ << A;
return nullptr;
case ParsedAttr::AT_FallThrough:
return handleFallThroughAttr(S, St, A, Range);
@@ -336,7 +339,7 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
// if we're here, then we parsed a known attribute, but didn't recognize
// it as a statement attribute => it is declaration attribute
S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt)
- << A.getName() << St->getBeginLoc();
+ << A << St->getBeginLoc();
return nullptr;
}
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 3212281cc34d..3f2d38630c36 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -20,9 +20,11 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/Stack.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Overload.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaInternal.h"
@@ -44,27 +46,7 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps,
return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc());
}
-namespace clang {
-/// [temp.constr.decl]p2: A template's associated constraints are
-/// defined as a single constraint-expression derived from the introduced
-/// constraint-expressions [ ... ].
-///
-/// \param Params The template parameter list and optional requires-clause.
-///
-/// \param FD The underlying templated function declaration for a function
-/// template.
-static Expr *formAssociatedConstraints(TemplateParameterList *Params,
- FunctionDecl *FD);
-}
-
-static Expr *clang::formAssociatedConstraints(TemplateParameterList *Params,
- FunctionDecl *FD) {
- // FIXME: Concepts: collect additional introduced constraint-expressions
- assert(!FD && "Cannot collect constraints from function declaration yet.");
- return Params->getRequiresClause();
-}
-
-/// Determine whether the declaration found is acceptable as the name
+/// \brief Determine whether the declaration found is acceptable as the name
/// of a template and, if so, return that template declaration. Otherwise,
/// returns null.
///
@@ -362,13 +344,27 @@ bool Sema::LookupTemplateName(LookupResult &Found,
// x->B::f, and we are looking into the type of the object.
assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
LookupCtx = computeDeclContext(ObjectType);
- IsDependent = !LookupCtx;
+ IsDependent = !LookupCtx && ObjectType->isDependentType();
assert((IsDependent || !ObjectType->isIncompleteType() ||
ObjectType->castAs<TagType>()->isBeingDefined()) &&
"Caller should have completed object type");
- // Template names cannot appear inside an Objective-C class or object type.
- if (ObjectType->isObjCObjectOrInterfaceType()) {
+ // Template names cannot appear inside an Objective-C class or object type
+ // or a vector type.
+ //
+ // FIXME: This is wrong. For example:
+ //
+ // template<typename T> using Vec = T __attribute__((ext_vector_type(4)));
+ // Vec<int> vi;
+ // vi.Vec<int>::~Vec<int>();
+ //
+ // ... should be accepted but we will not treat 'Vec' as a template name
+ // here. The right thing to do would be to check if the name is a valid
+ // vector component name, and look up a template name if not. And similarly
+ // for lookups into Objective-C class and object types, where the same
+ // problem can arise.
+ if (ObjectType->isObjCObjectOrInterfaceType() ||
+ ObjectType->isVectorType()) {
Found.clear();
return false;
}
@@ -630,7 +626,7 @@ void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName,
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<TemplateCandidateFilter>(*this);
+ return std::make_unique<TemplateCandidateFilter>(*this);
}
};
@@ -720,9 +716,13 @@ Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs) {
+ // DependentScopeDeclRefExpr::Create requires a valid QualifierLoc
+ NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
+ if (!QualifierLoc)
+ return ExprError();
+
return DependentScopeDeclRefExpr::Create(
- Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo,
- TemplateArgs);
+ Context, QualifierLoc, TemplateKWLoc, NameInfo, TemplateArgs);
}
@@ -830,15 +830,14 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
assert(PrevDecl->isTemplateParameter() && "Not a template parameter");
- // Microsoft Visual C++ permits template parameters to be shadowed.
- if (getLangOpts().MicrosoftExt)
- return;
-
// C++ [temp.local]p4:
// A template-parameter shall not be redeclared within its
// scope (including nested scopes).
- Diag(Loc, diag::err_template_param_shadow)
- << cast<NamedDecl>(PrevDecl)->getDeclName();
+ //
+ // Make this a warning when MSVC compatibility is requested.
+ unsigned DiagId = getLangOpts().MSVCCompat ? diag::ext_template_param_shadow
+ : diag::err_template_param_shadow;
+ Diag(Loc, DiagId) << cast<NamedDecl>(PrevDecl)->getDeclName();
Diag(PrevDecl->getLocation(), diag::note_template_param_here);
}
@@ -987,17 +986,16 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
assert(S->isTemplateParamScope() &&
"Template type parameter not in template parameter scope!");
- SourceLocation Loc = ParamNameLoc;
- if (!ParamName)
- Loc = KeyLoc;
-
bool IsParameterPack = EllipsisLoc.isValid();
- TemplateTypeParmDecl *Param
- = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(),
- KeyLoc, Loc, Depth, Position, ParamName,
- Typename, IsParameterPack);
+ TemplateTypeParmDecl *Param = TemplateTypeParmDecl::Create(
+ Context, Context.getTranslationUnitDecl(), KeyLoc, ParamNameLoc, Depth,
+ Position, ParamName, Typename, IsParameterPack);
Param->setAccess(AS_public);
+ if (Param->isParameterPack())
+ if (auto *LSI = getEnclosingLambda())
+ LSI->LocalPacks.push_back(Param);
+
if (ParamName) {
maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName);
@@ -1022,7 +1020,7 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
assert(DefaultTInfo && "expected source information for type");
// Check for unexpanded parameter packs.
- if (DiagnoseUnexpandedParameterPack(Loc, DefaultTInfo,
+ if (DiagnoseUnexpandedParameterPack(ParamNameLoc, DefaultTInfo,
UPPC_DefaultArgument))
return Param;
@@ -1082,9 +1080,6 @@ QualType Sema::CheckNonTypeTemplateParameterType(QualType T,
T->isMemberPointerType() ||
// -- std::nullptr_t.
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() ||
// Allow use of auto in template parameter declarations.
T->isUndeducedType()) {
// C++ [temp.param]p5: The top-level cv-qualifiers on the template-parameter
@@ -1097,9 +1092,18 @@ QualType Sema::CheckNonTypeTemplateParameterType(QualType T,
// A non-type template-parameter of type "array of T" or
// "function returning T" is adjusted to be of type "pointer to
// T" or "pointer to function returning T", respectively.
- else if (T->isArrayType() || T->isFunctionType())
+ if (T->isArrayType() || T->isFunctionType())
return Context.getDecayedType(T);
+ // If T is a dependent type, we can't do the check now, so we
+ // assume that it is well-formed. Note that stripping off the
+ // qualifiers here is not really correct if T turns out to be
+ // an array type, but we'll recompute the type everywhere it's
+ // used during instantiation, so that should be OK. (Using the
+ // qualified type is equally wrong.)
+ if (T->isDependentType())
+ return T.getUnqualifiedType();
+
Diag(Loc, diag::err_template_nontype_parm_bad_type)
<< T;
@@ -1196,6 +1200,10 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
if (Invalid)
Param->setInvalidDecl();
+ if (Param->isParameterPack())
+ if (auto *LSI = getEnclosingLambda())
+ LSI->LocalPacks.push_back(Param);
+
if (ParamName) {
maybeDiagnoseTemplateParameterShadow(*this, S, D.getIdentifierLoc(),
ParamName);
@@ -1259,6 +1267,10 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(Scope* S,
Name, Params);
Param->setAccess(AS_public);
+ if (Param->isParameterPack())
+ if (auto *LSI = getEnclosingLambda())
+ LSI->LocalPacks.push_back(Param);
+
// If the template template parameter has a name, then link the identifier
// into the scope and lookup mechanisms.
if (Name) {
@@ -1502,9 +1514,6 @@ DeclResult Sema::CheckClassTemplate(
}
}
- // TODO Memory management; associated constraints are not always stored.
- Expr *const CurAC = formAssociatedConstraints(TemplateParams, nullptr);
-
if (PrevClassTemplate) {
// Ensure that the template parameter lists are compatible. Skip this check
// for a friend in a dependent context: the template parameter list itself
@@ -1516,30 +1525,6 @@ DeclResult Sema::CheckClassTemplate(
TPL_TemplateMatch))
return true;
- // Check for matching associated constraints on redeclarations.
- const Expr *const PrevAC = PrevClassTemplate->getAssociatedConstraints();
- const bool RedeclACMismatch = [&] {
- if (!(CurAC || PrevAC))
- return false; // Nothing to check; no mismatch.
- if (CurAC && PrevAC) {
- llvm::FoldingSetNodeID CurACInfo, PrevACInfo;
- CurAC->Profile(CurACInfo, Context, /*Canonical=*/true);
- PrevAC->Profile(PrevACInfo, Context, /*Canonical=*/true);
- if (CurACInfo == PrevACInfo)
- return false; // All good; no mismatch.
- }
- return true;
- }();
-
- if (RedeclACMismatch) {
- Diag(CurAC ? CurAC->getBeginLoc() : NameLoc,
- diag::err_template_different_associated_constraints);
- Diag(PrevAC ? PrevAC->getBeginLoc() : PrevClassTemplate->getLocation(),
- diag::note_template_prev_declaration)
- << /*declaration*/ 0;
- return true;
- }
-
// C++ [temp.class]p4:
// In a redeclaration, partial specialization, explicit
// specialization or explicit instantiation of a class template,
@@ -1643,15 +1628,10 @@ DeclResult Sema::CheckClassTemplate(
AddMsStructLayoutForRecord(NewClass);
}
- // Attach the associated constraints when the declaration will not be part of
- // a decl chain.
- Expr *const ACtoAttach =
- PrevClassTemplate && ShouldAddRedecl ? nullptr : CurAC;
-
ClassTemplateDecl *NewTemplate
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
DeclarationName(Name), TemplateParams,
- NewClass, ACtoAttach);
+ NewClass);
if (ShouldAddRedecl)
NewTemplate->setPreviousDecl(PrevClassTemplate);
@@ -1690,6 +1670,7 @@ DeclResult Sema::CheckClassTemplate(
mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
AddPushedVisibilityAttribute(NewClass);
+ inferGslOwnerPointerAttribute(NewClass);
if (TUK != TUK_Friend) {
// Per C++ [basic.scope.temp]p2, skip the template parameter scopes.
@@ -3440,7 +3421,7 @@ bool Sema::resolveAssumedTemplateNameAsType(Scope *S, TemplateName &Name,
getAsTypeTemplateDecl(TC.getCorrectionDecl());
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<CandidateCallback>(*this);
+ return std::make_unique<CandidateCallback>(*this);
}
} FilterCCC;
@@ -4239,14 +4220,47 @@ void Sema::diagnoseMissingTemplateArguments(TemplateName Name,
ExprResult
Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
- const DeclarationNameInfo &NameInfo,
- ConceptDecl *Template,
- SourceLocation TemplateLoc,
+ SourceLocation TemplateKWLoc,
+ SourceLocation ConceptNameLoc,
+ NamedDecl *FoundDecl,
+ ConceptDecl *NamedConcept,
const TemplateArgumentListInfo *TemplateArgs) {
- // TODO: Do concept specialization here.
- Diag(NameInfo.getBeginLoc(), diag::err_concept_not_implemented) <<
- "concept specialization";
- return ExprError();
+ assert(NamedConcept && "A concept template id without a template?");
+
+ llvm::SmallVector<TemplateArgument, 4> Converted;
+ if (CheckTemplateArgumentList(NamedConcept, ConceptNameLoc,
+ const_cast<TemplateArgumentListInfo&>(*TemplateArgs),
+ /*PartialTemplateArgs=*/false, Converted,
+ /*UpdateArgsWithConversion=*/false))
+ return ExprError();
+
+ Optional<bool> IsSatisfied;
+ bool AreArgsDependent = false;
+ for (TemplateArgument &Arg : Converted) {
+ if (Arg.isDependent()) {
+ AreArgsDependent = true;
+ break;
+ }
+ }
+ if (!AreArgsDependent) {
+ InstantiatingTemplate Inst(*this, ConceptNameLoc,
+ InstantiatingTemplate::ConstraintsCheck{}, NamedConcept, Converted,
+ SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameLoc,
+ TemplateArgs->getRAngleLoc()));
+ MultiLevelTemplateArgumentList MLTAL;
+ MLTAL.addOuterTemplateArguments(Converted);
+ bool Satisfied;
+ if (CalculateConstraintSatisfaction(NamedConcept, MLTAL,
+ NamedConcept->getConstraintExpr(),
+ Satisfied))
+ return ExprError();
+ IsSatisfied = Satisfied;
+ }
+ return ConceptSpecializationExpr::Create(Context,
+ SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{},
+ TemplateKWLoc, ConceptNameLoc, FoundDecl, NamedConcept,
+ ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted,
+ IsSatisfied);
}
ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
@@ -4289,10 +4303,11 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
TemplateKWLoc, TemplateArgs);
}
- if (R.getAsSingle<ConceptDecl>() && !AnyDependentArguments()) {
- return CheckConceptTemplateId(SS, R.getLookupNameInfo(),
- R.getAsSingle<ConceptDecl>(),
- TemplateKWLoc, TemplateArgs);
+ if (R.getAsSingle<ConceptDecl>()) {
+ return CheckConceptTemplateId(SS, TemplateKWLoc,
+ R.getLookupNameInfo().getBeginLoc(),
+ R.getFoundDecl(),
+ R.getAsSingle<ConceptDecl>(), TemplateArgs);
}
// We don't want lookup warnings at this point.
@@ -4678,6 +4693,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
for (unsigned i = 0, e = Param->getDepth(); i != e; ++i)
TemplateArgLists.addOuterTemplateArguments(None);
+ Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext());
EnterExpressionEvaluationContext ConstantEvaluated(
SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists);
@@ -4895,9 +4911,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
if (NTTP->isParameterPack() && NTTP->isExpandedParameterPack())
NTTPType = NTTP->getExpansionType(ArgumentPackIndex);
- // FIXME: Do we need to substitute into parameters here if they're
- // instantiation-dependent but not dependent?
- if (NTTPType->isDependentType() &&
+ if (NTTPType->isInstantiationDependentType() &&
!isa<TemplateTemplateParmDecl>(Template) &&
!Template->getDeclContext()->isDependentContext()) {
// Do substitution on the type of the non-type template parameter.
@@ -5471,7 +5485,7 @@ namespace {
bool Visit##Class##Type(const Class##Type *) { return false; }
#define NON_CANONICAL_TYPE(Class, Parent) \
bool Visit##Class##Type(const Class##Type *) { return false; }
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
bool VisitTagDecl(const TagDecl *Tag);
bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS);
@@ -5847,7 +5861,7 @@ static bool CheckTemplateArgumentIsCompatibleWithParameter(
Expr *Arg, QualType ArgType) {
bool ObjCLifetimeConversion;
if (ParamType->isPointerType() &&
- !ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType() &&
+ !ParamType->castAs<PointerType>()->getPointeeType()->isFunctionType() &&
S.IsQualificationConversion(ArgType, ParamType, false,
ObjCLifetimeConversion)) {
// For pointer-to-object types, qualification conversions are
@@ -6399,8 +6413,11 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
}
// If either the parameter has a dependent type or the argument is
- // type-dependent, there's nothing we can check now.
- if (ParamType->isDependentType() || Arg->isTypeDependent()) {
+ // type-dependent, there's nothing we can check now. The argument only
+ // contains an unexpanded pack during partial ordering, and there's
+ // nothing more we can check in that case.
+ if (ParamType->isDependentType() || Arg->isTypeDependent() ||
+ Arg->containsUnexpandedParameterPack()) {
// Force the argument to the type of the parameter to maintain invariants.
auto *PE = dyn_cast<PackExpansionExpr>(Arg);
if (PE)
@@ -6720,20 +6737,20 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// overloaded functions (or a pointer to such), the matching
// function is selected from the set (13.4).
(ParamType->isPointerType() &&
- ParamType->getAs<PointerType>()->getPointeeType()->isFunctionType()) ||
+ ParamType->castAs<PointerType>()->getPointeeType()->isFunctionType()) ||
// -- For a non-type template-parameter of type reference to
// function, no conversions apply. If the template-argument
// represents a set of overloaded functions, the matching
// function is selected from the set (13.4).
(ParamType->isReferenceType() &&
- ParamType->getAs<ReferenceType>()->getPointeeType()->isFunctionType()) ||
+ ParamType->castAs<ReferenceType>()->getPointeeType()->isFunctionType()) ||
// -- For a non-type template-parameter of type pointer to
// member function, no conversions apply. If the
// template-argument represents a set of overloaded member
// functions, the matching member function is selected from
// the set (13.4).
(ParamType->isMemberPointerType() &&
- ParamType->getAs<MemberPointerType>()->getPointeeType()
+ ParamType->castAs<MemberPointerType>()->getPointeeType()
->isFunctionType())) {
if (Arg->getType() == Context.OverloadTy) {
@@ -7198,6 +7215,9 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
TemplateArgLoc);
}
+ // TODO: Concepts: Match immediately-introduced-constraint for type
+ // constraints
+
return true;
}
@@ -7223,6 +7243,15 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S,
<< SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc());
}
+static void
+DiagnoseTemplateParameterListRequiresClauseMismatch(Sema &S,
+ TemplateParameterList *New,
+ TemplateParameterList *Old){
+ S.Diag(New->getTemplateLoc(), diag::err_template_different_requires_clause);
+ S.Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration)
+ << /*declaration*/0;
+}
+
/// Determine whether the given template parameter lists are
/// equivalent.
///
@@ -7312,6 +7341,27 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
return false;
}
+ if (Kind != TPL_TemplateTemplateArgumentMatch) {
+ const Expr *NewRC = New->getRequiresClause();
+ const Expr *OldRC = Old->getRequiresClause();
+ if (!NewRC != !OldRC) {
+ if (Complain)
+ DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old);
+ return false;
+ }
+
+ if (NewRC) {
+ llvm::FoldingSetNodeID OldRCID, NewRCID;
+ OldRC->Profile(OldRCID, Context, /*Canonical=*/true);
+ NewRC->Profile(NewRCID, Context, /*Canonical=*/true);
+ if (OldRCID != NewRCID) {
+ if (Complain)
+ DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old);
+ return false;
+ }
+ }
+ }
+
return true;
}
@@ -8020,24 +8070,10 @@ Decl *Sema::ActOnConceptDefinition(Scope *S,
ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name,
TemplateParameterLists.front(),
ConstraintExpr);
-
- if (!ConstraintExpr->isTypeDependent() &&
- ConstraintExpr->getType() != Context.BoolTy) {
- // C++2a [temp.constr.atomic]p3:
- // E shall be a constant expression of type bool.
- // TODO: Do this check for individual atomic constraints
- // and not the constraint expression. Probably should do it in
- // ParseConstraintExpression.
- Diag(ConstraintExpr->getSourceRange().getBegin(),
- diag::err_concept_initialized_with_non_bool_type)
- << ConstraintExpr->getType();
- NewDecl->setInvalidDecl();
- }
-
- if (NewDecl->getAssociatedConstraints()) {
+
+ if (NewDecl->hasAssociatedConstraints()) {
// C++2a [temp.concept]p4:
// A concept shall not have associated constraints.
- // TODO: Make a test once we have actual associated constraints.
Diag(NameLoc, diag::err_concept_no_associated_constraints);
NewDecl->setInvalidDecl();
}
@@ -8453,7 +8489,7 @@ bool Sema::CheckFunctionTemplateSpecialization(
// candidates at once, to get proper sorting and limiting.
for (auto *OldND : Previous) {
if (auto *OldFD = dyn_cast<FunctionDecl>(OldND->getUnderlyingDecl()))
- NoteOverloadCandidate(OldND, OldFD, FD->getType(), false);
+ NoteOverloadCandidate(OldND, OldFD, CRK_None, FD->getType(), false);
}
FailedCandidates.NoteCandidates(*this, FD->getLocation());
return true;
@@ -10282,7 +10318,7 @@ void Sema::MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD,
if (!FD)
return;
- auto LPT = llvm::make_unique<LateParsedTemplate>();
+ auto LPT = std::make_unique<LateParsedTemplate>();
// Take tokens to avoid allocations
LPT->Toks.swap(Toks);
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index b55a232d26c2..64ef819e30d4 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -1486,7 +1486,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
#define NON_CANONICAL_TYPE(Class, Base) \
case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class);
#define TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
case Type::TemplateTypeParm:
case Type::SubstTemplateTypeParmPack:
@@ -3093,6 +3093,13 @@ Sema::SubstituteExplicitTemplateArguments(
Function->getTypeSpecStartLoc(), Function->getDeclName());
if (ResultType.isNull() || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
+ // CUDA: Kernel function must have 'void' return type.
+ if (getLangOpts().CUDA)
+ if (Function->hasAttr<CUDAGlobalAttr>() && !ResultType->isVoidType()) {
+ Diag(Function->getLocation(), diag::err_kern_type_not_void_return)
+ << Function->getType() << Function->getSourceRange();
+ return TDK_SubstitutionFailure;
+ }
}
// Instantiate the types of each of the function parameters given the
@@ -3702,6 +3709,12 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList(
return Sema::TDK_Success;
}
+ // Resolving a core issue: a braced-init-list containing any designators is
+ // a non-deduced context.
+ for (Expr *E : ILE->inits())
+ if (isa<DesignatedInitExpr>(E))
+ return Sema::TDK_Success;
+
// Deduction only needs to be done for dependent types.
if (ElTy->isDependentType()) {
for (Expr *E : ILE->inits()) {
@@ -3813,8 +3826,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
if (Args.size() < Function->getMinRequiredArguments() && !PartialOverloading)
return TDK_TooFewArguments;
else if (TooManyArguments(NumParams, Args.size(), PartialOverloading)) {
- const FunctionProtoType *Proto
- = Function->getType()->getAs<FunctionProtoType>();
+ const auto *Proto = Function->getType()->castAs<FunctionProtoType>();
if (Proto->isTemplateVariadic())
/* Do nothing */;
else if (!Proto->isVariadic())
@@ -3952,11 +3964,8 @@ QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType,
if (ArgFunctionType.isNull())
return ArgFunctionType;
- const FunctionProtoType *FunctionTypeP =
- FunctionType->castAs<FunctionProtoType>();
- const FunctionProtoType *ArgFunctionTypeP =
- ArgFunctionType->getAs<FunctionProtoType>();
-
+ const auto *FunctionTypeP = FunctionType->castAs<FunctionProtoType>();
+ const auto *ArgFunctionTypeP = ArgFunctionType->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = ArgFunctionTypeP->getExtProtoInfo();
bool Rebuild = false;
@@ -4509,6 +4518,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
if (!Type.getType().getNonReferenceType()->getAs<AutoType>())
return DAR_Failed;
+ // Resolving a core issue: a braced-init-list containing any designators is
+ // a non-deduced context.
+ for (Expr *E : InitList->inits())
+ if (isa<DesignatedInitExpr>(E))
+ return DAR_Failed;
+
SourceRange DeducedFromInitRange;
for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) {
Expr *Init = InitList->getInit(i);
@@ -4632,8 +4647,11 @@ bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
// We might need to deduce the return type by instantiating the definition
// of the operator() function.
- if (CallOp->getReturnType()->isUndeducedType())
- InstantiateFunctionDefinition(Loc, CallOp);
+ if (CallOp->getReturnType()->isUndeducedType()) {
+ runWithSufficientStackSpace(Loc, [&] {
+ InstantiateFunctionDefinition(Loc, CallOp);
+ });
+ }
}
if (CallOp->isInvalidDecl())
@@ -4654,8 +4672,11 @@ bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
return false;
}
- if (FD->getTemplateInstantiationPattern())
- InstantiateFunctionDefinition(Loc, FD);
+ if (FD->getTemplateInstantiationPattern()) {
+ runWithSufficientStackSpace(Loc, [&] {
+ InstantiateFunctionDefinition(Loc, FD);
+ });
+ }
bool StillUndeduced = FD->getReturnType()->isUndeducedType();
if (StillUndeduced && Diagnose && !FD->isInvalidDecl()) {
@@ -5590,7 +5611,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
#define ABSTRACT_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base)
#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
break;
}
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 973f564d3058..0daa33cfbef5 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/PrettyDeclStackTrace.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/Stack.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
@@ -197,12 +198,15 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
case ExplicitTemplateArgumentSubstitution:
case DeducedTemplateArgumentSubstitution:
case PriorTemplateArgumentSubstitution:
+ case ConstraintsCheck:
return true;
case DefaultTemplateArgumentChecking:
case DeclaringSpecialMember:
case DefiningSynthesizedFunction:
case ExceptionSpecEvaluation:
+ case ConstraintSubstitution:
+ case RewritingOperatorAsSpaceship:
return false;
// This function should never be called when Kind's value is Memoization.
@@ -357,6 +361,24 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
PointOfInstantiation, InstantiationRange, Param, Template,
TemplateArgs) {}
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ConstraintsCheck, TemplateDecl *Template,
+ ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::ConstraintsCheck,
+ PointOfInstantiation, InstantiationRange, Template, nullptr,
+ TemplateArgs) {}
+
+Sema::InstantiatingTemplate::InstantiatingTemplate(
+ Sema &SemaRef, SourceLocation PointOfInstantiation,
+ ConstraintSubstitution, TemplateDecl *Template,
+ sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
+ : InstantiatingTemplate(
+ SemaRef, CodeSynthesisContext::ConstraintSubstitution,
+ PointOfInstantiation, InstantiationRange, Template, nullptr,
+ {}, &DeductionInfo) {}
+
void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext;
InNonInstantiationSFINAEContext = false;
@@ -365,6 +387,11 @@ void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {
if (!Ctx.isInstantiationRecord())
++NonInstantiationEntries;
+
+ // Check to see if we're low on stack space. We can't do anything about this
+ // from here, but we can at least warn the user.
+ if (isStackNearlyExhausted())
+ warnStackExhausted(Ctx.PointOfInstantiation);
}
void Sema::popCodeSynthesisContext() {
@@ -656,8 +683,37 @@ void Sema::PrintInstantiationStack() {
break;
}
+ case CodeSynthesisContext::RewritingOperatorAsSpaceship:
+ Diags.Report(Active->Entity->getLocation(),
+ diag::note_rewriting_operator_as_spaceship);
+ break;
+
case CodeSynthesisContext::Memoization:
break;
+
+ case CodeSynthesisContext::ConstraintsCheck:
+ if (auto *CD = dyn_cast<ConceptDecl>(Active->Entity)) {
+ SmallVector<char, 128> TemplateArgsStr;
+ llvm::raw_svector_ostream OS(TemplateArgsStr);
+ CD->printName(OS);
+ printTemplateArgumentList(OS, Active->template_arguments(),
+ getPrintingPolicy());
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_concept_specialization_here)
+ << OS.str()
+ << Active->InstantiationRange;
+ break;
+ }
+ // TODO: Concepts - implement this for constrained templates and partial
+ // specializations.
+ llvm_unreachable("only concept constraints are supported right now");
+ break;
+
+ case CodeSynthesisContext::ConstraintSubstitution:
+ Diags.Report(Active->PointOfInstantiation,
+ diag::note_constraint_substitution_here)
+ << Active->InstantiationRange;
+ break;
}
}
}
@@ -681,6 +737,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
LLVM_FALLTHROUGH;
case CodeSynthesisContext::DefaultFunctionArgumentInstantiation:
case CodeSynthesisContext::ExceptionSpecInstantiation:
+ case CodeSynthesisContext::ConstraintsCheck:
// This is a template instantiation, so there is no SFINAE.
return None;
@@ -694,13 +751,16 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution:
case CodeSynthesisContext::DeducedTemplateArgumentSubstitution:
- // We're either substitution explicitly-specified template arguments
- // or deduced template arguments, so SFINAE applies.
+ case CodeSynthesisContext::ConstraintSubstitution:
+ // We're either substituting explicitly-specified template arguments
+ // or deduced template arguments or a constraint expression, so SFINAE
+ // applies.
assert(Active->DeductionInfo && "Missing deduction info pointer");
return Active->DeductionInfo;
case CodeSynthesisContext::DeclaringSpecialMember:
case CodeSynthesisContext::DefiningSynthesizedFunction:
+ case CodeSynthesisContext::RewritingOperatorAsSpaceship:
// This happens in a context unrelated to template instantiation, so
// there is no SFINAE.
return None;
@@ -1252,9 +1312,8 @@ TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) {
// Create new LoopHintValueAttr with integral expression in place of the
// non-type template parameter.
- return LoopHintAttr::CreateImplicit(
- getSema().Context, LH->getSemanticSpelling(), LH->getOption(),
- LH->getState(), TransformedExpr, LH->getRange());
+ return LoopHintAttr::CreateImplicit(getSema().Context, LH->getOption(),
+ LH->getState(), TransformedExpr, *LH);
}
ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 67343d11d333..d1ad304e62e4 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -86,15 +86,13 @@ static void instantiateDependentAlignedAttr(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Aligned->getAlignmentExpr(), TemplateArgs);
if (!Result.isInvalid())
- S.AddAlignedAttr(Aligned->getLocation(), New, Result.getAs<Expr>(),
- Aligned->getSpellingListIndex(), IsPackExpansion);
+ S.AddAlignedAttr(New, *Aligned, Result.getAs<Expr>(), IsPackExpansion);
} else {
TypeSourceInfo *Result = S.SubstType(Aligned->getAlignmentType(),
TemplateArgs, Aligned->getLocation(),
DeclarationName());
if (Result)
- S.AddAlignedAttr(Aligned->getLocation(), New, Result,
- Aligned->getSpellingListIndex(), IsPackExpansion);
+ S.AddAlignedAttr(New, *Aligned, Result, IsPackExpansion);
}
}
@@ -156,8 +154,7 @@ static void instantiateDependentAssumeAlignedAttr(
OE = Result.getAs<Expr>();
}
- S.AddAssumeAlignedAttr(Aligned->getLocation(), New, E, OE,
- Aligned->getSpellingListIndex());
+ S.AddAssumeAlignedAttr(New, *Aligned, E, OE);
}
static void instantiateDependentAlignValueAttr(
@@ -168,8 +165,7 @@ static void instantiateDependentAlignValueAttr(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult Result = S.SubstExpr(Aligned->getAlignment(), TemplateArgs);
if (!Result.isInvalid())
- S.AddAlignValueAttr(Aligned->getLocation(), New, Result.getAs<Expr>(),
- Aligned->getSpellingListIndex());
+ S.AddAlignValueAttr(New, *Aligned, Result.getAs<Expr>());
}
static void instantiateDependentAllocAlignAttr(
@@ -179,8 +175,7 @@ static void instantiateDependentAllocAlignAttr(
S.getASTContext(),
llvm::APInt(64, Align->getParamIndex().getSourceIndex()),
S.getASTContext().UnsignedLongLongTy, Align->getLocation());
- S.AddAllocAlignAttr(Align->getLocation(), New, Param,
- Align->getSpellingListIndex());
+ S.AddAllocAlignAttr(New, *Align, Param);
}
static Expr *instantiateDependentFunctionAttrCondition(
@@ -221,9 +216,8 @@ static void instantiateDependentEnableIfAttr(
S, TemplateArgs, EIA, EIA->getCond(), Tmpl, New);
if (Cond)
- New->addAttr(new (S.getASTContext()) EnableIfAttr(
- EIA->getLocation(), S.getASTContext(), Cond, EIA->getMessage(),
- EIA->getSpellingListIndex()));
+ New->addAttr(new (S.getASTContext()) EnableIfAttr(S.getASTContext(), *EIA,
+ Cond, EIA->getMessage()));
}
static void instantiateDependentDiagnoseIfAttr(
@@ -234,9 +228,8 @@ static void instantiateDependentDiagnoseIfAttr(
if (Cond)
New->addAttr(new (S.getASTContext()) DiagnoseIfAttr(
- DIA->getLocation(), S.getASTContext(), Cond, DIA->getMessage(),
- DIA->getDiagnosticType(), DIA->getArgDependent(), New,
- DIA->getSpellingListIndex()));
+ S.getASTContext(), *DIA, Cond, DIA->getMessage(),
+ DIA->getDiagnosticType(), DIA->getArgDependent(), New));
}
// Constructs and adds to New a new instance of CUDALaunchBoundsAttr using
@@ -261,16 +254,15 @@ static void instantiateDependentCUDALaunchBoundsAttr(
MinBlocks = Result.getAs<Expr>();
}
- S.AddLaunchBoundsAttr(Attr.getLocation(), New, MaxThreads, MinBlocks,
- Attr.getSpellingListIndex());
+ S.AddLaunchBoundsAttr(New, Attr, MaxThreads, MinBlocks);
}
static void
instantiateDependentModeAttr(Sema &S,
const MultiLevelTemplateArgumentList &TemplateArgs,
const ModeAttr &Attr, Decl *New) {
- S.AddModeAttr(Attr.getRange(), New, Attr.getMode(),
- Attr.getSpellingListIndex(), /*InInstantiation=*/true);
+ S.AddModeAttr(New, Attr, Attr.getMode(),
+ /*InInstantiation=*/true);
}
/// Instantiation of 'declare simd' attribute and its arguments.
@@ -356,6 +348,67 @@ static void instantiateOMPDeclareSimdDeclAttr(
Attr.getRange());
}
+/// Instantiation of 'declare variant' attribute and its arguments.
+static void instantiateOMPDeclareVariantAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+ const OMPDeclareVariantAttr &Attr, Decl *New) {
+ // Allow 'this' in clauses with varlists.
+ if (auto *FTD = dyn_cast<FunctionTemplateDecl>(New))
+ New = FTD->getTemplatedDecl();
+ auto *FD = cast<FunctionDecl>(New);
+ auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(FD->getDeclContext());
+
+ auto &&SubstExpr = [FD, ThisContext, &S, &TemplateArgs](Expr *E) {
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
+ if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+ Sema::ContextRAII SavedContext(S, FD);
+ LocalInstantiationScope Local(S);
+ if (FD->getNumParams() > PVD->getFunctionScopeIndex())
+ Local.InstantiatedLocal(
+ PVD, FD->getParamDecl(PVD->getFunctionScopeIndex()));
+ return S.SubstExpr(E, TemplateArgs);
+ }
+ Sema::CXXThisScopeRAII ThisScope(S, ThisContext, Qualifiers(),
+ FD->isCXXInstanceMember());
+ return S.SubstExpr(E, TemplateArgs);
+ };
+
+ // Substitute a single OpenMP clause, which is a potentially-evaluated
+ // full-expression.
+ auto &&Subst = [&SubstExpr, &S](Expr *E) {
+ EnterExpressionEvaluationContext Evaluated(
+ S, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
+ ExprResult Res = SubstExpr(E);
+ if (Res.isInvalid())
+ return Res;
+ return S.ActOnFinishFullExpr(Res.get(), false);
+ };
+
+ ExprResult VariantFuncRef;
+ if (Expr *E = Attr.getVariantFuncRef())
+ VariantFuncRef = Subst(E);
+
+ ExprResult Score;
+ if (Expr *E = Attr.getScore())
+ Score = Subst(E);
+
+ // Check function/variant ref.
+ Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
+ S.checkOpenMPDeclareVariantFunction(
+ S.ConvertDeclToDeclGroup(New), VariantFuncRef.get(), Attr.getRange());
+ if (!DeclVarData)
+ return;
+ // Instantiate the attribute.
+ Sema::OpenMPDeclareVariantCtsSelectorData Data(
+ Attr.getCtxSelectorSet(), Attr.getCtxSelector(),
+ llvm::makeMutableArrayRef(Attr.implVendors_begin(),
+ Attr.implVendors_size()),
+ Score);
+ S.ActOnOpenMPDeclareVariantDirective(DeclVarData.getValue().first,
+ DeclVarData.getValue().second,
+ Attr.getRange(), Data);
+}
+
static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AMDGPUFlatWorkGroupSizeAttr &Attr, Decl *New) {
@@ -373,8 +426,7 @@ static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
return;
Expr *MaxExpr = Result.getAs<Expr>();
- S.addAMDGPUFlatWorkGroupSizeAttr(Attr.getLocation(), New, MinExpr, MaxExpr,
- Attr.getSpellingListIndex());
+ S.addAMDGPUFlatWorkGroupSizeAttr(New, Attr, MinExpr, MaxExpr);
}
static ExplicitSpecifier
@@ -420,8 +472,7 @@ static void instantiateDependentAMDGPUWavesPerEUAttr(
MaxExpr = Result.getAs<Expr>();
}
- S.addAMDGPUWavesPerEUAttr(Attr.getLocation(), New, MinExpr, MaxExpr,
- Attr.getSpellingListIndex());
+ S.addAMDGPUWavesPerEUAttr(New, Attr, MinExpr, MaxExpr);
}
void Sema::InstantiateAttrsForDecl(
@@ -470,14 +521,12 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}
- const AssumeAlignedAttr *AssumeAligned = dyn_cast<AssumeAlignedAttr>(TmplAttr);
- if (AssumeAligned) {
+ if (const auto *AssumeAligned = dyn_cast<AssumeAlignedAttr>(TmplAttr)) {
instantiateDependentAssumeAlignedAttr(*this, TemplateArgs, AssumeAligned, New);
continue;
}
- const AlignValueAttr *AlignValue = dyn_cast<AlignValueAttr>(TmplAttr);
- if (AlignValue) {
+ if (const auto *AlignValue = dyn_cast<AlignValueAttr>(TmplAttr)) {
instantiateDependentAlignValueAttr(*this, TemplateArgs, AlignValue, New);
continue;
}
@@ -500,14 +549,14 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}
- if (const CUDALaunchBoundsAttr *CUDALaunchBounds =
+ if (const auto *CUDALaunchBounds =
dyn_cast<CUDALaunchBoundsAttr>(TmplAttr)) {
instantiateDependentCUDALaunchBoundsAttr(*this, TemplateArgs,
*CUDALaunchBounds, New);
continue;
}
- if (const ModeAttr *Mode = dyn_cast<ModeAttr>(TmplAttr)) {
+ if (const auto *Mode = dyn_cast<ModeAttr>(TmplAttr)) {
instantiateDependentModeAttr(*this, TemplateArgs, *Mode, New);
continue;
}
@@ -517,13 +566,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}
- if (const AMDGPUFlatWorkGroupSizeAttr *AMDGPUFlatWorkGroupSize =
+ if (const auto *OMPAttr = dyn_cast<OMPDeclareVariantAttr>(TmplAttr)) {
+ instantiateOMPDeclareVariantAttr(*this, TemplateArgs, *OMPAttr, New);
+ continue;
+ }
+
+ if (const auto *AMDGPUFlatWorkGroupSize =
dyn_cast<AMDGPUFlatWorkGroupSizeAttr>(TmplAttr)) {
instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
*this, TemplateArgs, *AMDGPUFlatWorkGroupSize, New);
}
- if (const AMDGPUWavesPerEUAttr *AMDGPUFlatWorkGroupSize =
+ if (const auto *AMDGPUFlatWorkGroupSize =
dyn_cast<AMDGPUWavesPerEUAttr>(TmplAttr)) {
instantiateDependentAMDGPUWavesPerEUAttr(*this, TemplateArgs,
*AMDGPUFlatWorkGroupSize, New);
@@ -537,21 +591,30 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
}
}
- if (auto ABIAttr = dyn_cast<ParameterABIAttr>(TmplAttr)) {
- AddParameterABIAttr(ABIAttr->getRange(), New, ABIAttr->getABI(),
- ABIAttr->getSpellingListIndex());
+ if (const auto *ABIAttr = dyn_cast<ParameterABIAttr>(TmplAttr)) {
+ AddParameterABIAttr(New, *ABIAttr, ABIAttr->getABI());
continue;
}
if (isa<NSConsumedAttr>(TmplAttr) || isa<OSConsumedAttr>(TmplAttr) ||
isa<CFConsumedAttr>(TmplAttr)) {
- AddXConsumedAttr(New, TmplAttr->getRange(),
- TmplAttr->getSpellingListIndex(),
- attrToRetainOwnershipKind(TmplAttr),
+ AddXConsumedAttr(New, *TmplAttr, attrToRetainOwnershipKind(TmplAttr),
/*template instantiation=*/true);
continue;
}
+ if (auto *A = dyn_cast<PointerAttr>(TmplAttr)) {
+ if (!New->hasAttr<PointerAttr>())
+ New->addAttr(A->clone(Context));
+ continue;
+ }
+
+ if (auto *A = dyn_cast<OwnerAttr>(TmplAttr)) {
+ if (!New->hasAttr<OwnerAttr>())
+ New->addAttr(A->clone(Context));
+ continue;
+ }
+
assert(!TmplAttr->isPackExpansion());
if (TmplAttr->isLateParsed() && LateAttrs) {
// Late parsed attributes must be instantiated and attached after the
@@ -711,6 +774,9 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
+ if (D->getUnderlyingType()->getAs<DependentNameType>())
+ SemaRef.inferGslPointerAttribute(Typedef);
+
Typedef->setAccess(D->getAccess());
return Typedef;
@@ -2090,10 +2156,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
Constructor->getConstexprKind());
Method->setRangeEnd(Constructor->getEndLoc());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
- Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
- StartLoc, NameInfo, T, TInfo,
- Destructor->isInlineSpecified(),
- false);
+ Method = CXXDestructorDecl::Create(
+ SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
+ Destructor->isInlineSpecified(), false, Destructor->getConstexprKind());
Method->setRangeEnd(Destructor->getEndLoc());
} else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
Method = CXXConversionDecl::Create(
@@ -2339,6 +2404,7 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(),
D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack());
Inst->setAccess(AS_public);
+ Inst->setImplicit(D->isImplicit());
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
TypeSourceInfo *InstantiatedDefaultArg =
@@ -2485,6 +2551,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI);
Param->setAccess(AS_public);
+ Param->setImplicit(D->isImplicit());
if (Invalid)
Param->setInvalidDecl();
@@ -2628,6 +2695,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
D->getDefaultArgument().getTemplateNameLoc()));
}
Param->setAccess(AS_public);
+ Param->setImplicit(D->isImplicit());
// Introduce this template parameter's instantiation into the instantiation
// scope.
@@ -3415,7 +3483,11 @@ Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
if (D->isInvalidDecl())
return nullptr;
- return Instantiator.Visit(D);
+ Decl *SubstD;
+ runWithSufficientStackSpace(D->getLocation(), [&] {
+ SubstD = Instantiator.Visit(D);
+ });
+ return SubstD;
}
/// Instantiates a nested template parameter list in the current
@@ -3443,14 +3515,21 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
if (Invalid)
return nullptr;
- // Note: we substitute into associated constraints later
- Expr *const UninstantiatedRequiresClause = L->getRequiresClause();
+ // FIXME: Concepts: Substitution into requires clause should only happen when
+ // checking satisfaction.
+ Expr *InstRequiresClause = nullptr;
+ if (Expr *E = L->getRequiresClause()) {
+ ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs);
+ if (Res.isInvalid() || !Res.isUsable()) {
+ return nullptr;
+ }
+ InstRequiresClause = Res.get();
+ }
TemplateParameterList *InstL
= TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
L->getLAngleLoc(), Params,
- L->getRAngleLoc(),
- UninstantiatedRequiresClause);
+ L->getRAngleLoc(), InstRequiresClause);
return InstL;
}
@@ -5217,11 +5296,11 @@ DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC,
/// template struct X<int>;
/// \endcode
///
-/// In the instantiation of <tt>X<int>::getKind()</tt>, we need to map the
-/// \p EnumConstantDecl for \p KnownValue (which refers to
-/// <tt>X<T>::<Kind>::KnownValue</tt>) to its instantiation
-/// (<tt>X<int>::<Kind>::KnownValue</tt>). \p FindInstantiatedDecl performs
-/// this mapping from within the instantiation of <tt>X<int></tt>.
+/// In the instantiation of X<int>::getKind(), we need to map the \p
+/// EnumConstantDecl for \p KnownValue (which refers to
+/// X<T>::<Kind>::KnownValue) to its instantiation (X<int>::<Kind>::KnownValue).
+/// \p FindInstantiatedDecl performs this mapping from within the instantiation
+/// of X<int>.
NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool FindingInstantiatedContext) {
@@ -5312,20 +5391,6 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
return cast<LabelDecl>(Inst);
}
- // For variable template specializations, update those that are still
- // type-dependent.
- if (VarTemplateSpecializationDecl *VarSpec =
- dyn_cast<VarTemplateSpecializationDecl>(D)) {
- bool InstantiationDependent = false;
- const TemplateArgumentListInfo &VarTemplateArgs =
- VarSpec->getTemplateArgsInfo();
- if (TemplateSpecializationType::anyDependentTemplateArguments(
- VarTemplateArgs, InstantiationDependent))
- D = cast<NamedDecl>(
- SubstDecl(D, VarSpec->getDeclContext(), TemplateArgs));
- return D;
- }
-
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
if (!Record->isDependentContext())
return D;
@@ -5450,11 +5515,23 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
// find it. Does that ever matter?
if (auto Name = D->getDeclName()) {
DeclarationNameInfo NameInfo(Name, D->getLocation());
- Name = SubstDeclarationNameInfo(NameInfo, TemplateArgs).getName();
+ DeclarationNameInfo NewNameInfo =
+ SubstDeclarationNameInfo(NameInfo, TemplateArgs);
+ Name = NewNameInfo.getName();
if (!Name)
return nullptr;
DeclContext::lookup_result Found = ParentDC->lookup(Name);
- Result = findInstantiationOf(Context, D, Found.begin(), Found.end());
+
+ if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) {
+ VarTemplateDecl *Templ = cast_or_null<VarTemplateDecl>(
+ findInstantiationOf(Context, VTSD->getSpecializedTemplate(),
+ Found.begin(), Found.end()));
+ if (!Templ)
+ return nullptr;
+ Result = getVarTemplateSpecialization(
+ Templ, &VTSD->getTemplateArgsInfo(), NewNameInfo, SourceLocation());
+ } else
+ Result = findInstantiationOf(Context, D, Found.begin(), Found.end());
} else {
// Since we don't have a name for the entity we're looking for,
// our only option is to walk through all of the declarations to
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index d97626551a41..975d6620c06f 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -294,44 +294,58 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
return false;
// If we are within a lambda expression and referencing a pack that is not
- // a parameter of the lambda itself, that lambda contains an unexpanded
+ // declared within the lambda itself, that lambda contains an unexpanded
// parameter pack, and we are done.
// FIXME: Store 'Unexpanded' on the lambda so we don't need to recompute it
// later.
SmallVector<UnexpandedParameterPack, 4> LambdaParamPackReferences;
- for (unsigned N = FunctionScopes.size(); N; --N) {
- sema::FunctionScopeInfo *Func = FunctionScopes[N-1];
- // We do not permit pack expansion that would duplicate a statement
- // expression, not even within a lambda.
- // FIXME: We could probably support this for statement expressions that do
- // not contain labels, and for pack expansions that expand both the stmt
- // expr and the enclosing lambda.
- if (std::any_of(
- Func->CompoundScopes.begin(), Func->CompoundScopes.end(),
- [](sema::CompoundScopeInfo &CSI) { return CSI.IsStmtExpr; }))
- break;
+ if (auto *LSI = getEnclosingLambda()) {
+ for (auto &Pack : Unexpanded) {
+ auto DeclaresThisPack = [&](NamedDecl *LocalPack) {
+ if (auto *TTPT = Pack.first.dyn_cast<const TemplateTypeParmType *>()) {
+ auto *TTPD = dyn_cast<TemplateTypeParmDecl>(LocalPack);
+ return TTPD && TTPD->getTypeForDecl() == TTPT;
+ }
+ return declaresSameEntity(Pack.first.get<NamedDecl *>(), LocalPack);
+ };
+ if (std::find_if(LSI->LocalPacks.begin(), LSI->LocalPacks.end(),
+ DeclaresThisPack) != LSI->LocalPacks.end())
+ LambdaParamPackReferences.push_back(Pack);
+ }
- if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Func)) {
- if (N == FunctionScopes.size()) {
- for (auto &Pack : Unexpanded) {
- auto *VD = dyn_cast_or_null<VarDecl>(
- Pack.first.dyn_cast<NamedDecl *>());
- if (VD && VD->getDeclContext() == LSI->CallOperator)
- LambdaParamPackReferences.push_back(Pack);
+ if (LambdaParamPackReferences.empty()) {
+ // Construct in lambda only references packs declared outside the lambda.
+ // That's OK for now, but the lambda itself is considered to contain an
+ // unexpanded pack in this case, which will require expansion outside the
+ // lambda.
+
+ // We do not permit pack expansion that would duplicate a statement
+ // expression, not even within a lambda.
+ // FIXME: We could probably support this for statement expressions that
+ // do not contain labels.
+ // FIXME: This is insufficient to detect this problem; consider
+ // f( ({ bad: 0; }) + pack ... );
+ bool EnclosingStmtExpr = false;
+ for (unsigned N = FunctionScopes.size(); N; --N) {
+ sema::FunctionScopeInfo *Func = FunctionScopes[N-1];
+ if (std::any_of(
+ Func->CompoundScopes.begin(), Func->CompoundScopes.end(),
+ [](sema::CompoundScopeInfo &CSI) { return CSI.IsStmtExpr; })) {
+ EnclosingStmtExpr = true;
+ break;
}
+ // Coumpound-statements outside the lambda are OK for now; we'll check
+ // for those when we finish handling the lambda.
+ if (Func == LSI)
+ break;
}
- // If we have references to a parameter pack of the innermost enclosing
- // lambda, only diagnose those ones. We don't know whether any other
- // unexpanded parameters referenced herein are actually unexpanded;
- // they might be expanded at an outer level.
- if (!LambdaParamPackReferences.empty()) {
- Unexpanded = LambdaParamPackReferences;
- break;
+ if (!EnclosingStmtExpr) {
+ LSI->ContainsUnexpandedParameterPack = true;
+ return false;
}
-
- LSI->ContainsUnexpandedParameterPack = true;
- return false;
+ } else {
+ Unexpanded = LambdaParamPackReferences;
}
}
@@ -937,7 +951,7 @@ class ParameterPackValidatorCCC final : public CorrectionCandidateCallback {
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<ParameterPackValidatorCCC>(*this);
+ return std::make_unique<ParameterPackValidatorCCC>(*this);
}
};
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 29acf6177eb9..fccdb2bc2e2c 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -82,7 +82,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr,
}
SourceLocation loc = attr.getLoc();
- StringRef name = attr.getName()->getName();
+ StringRef name = attr.getAttrName()->getName();
// The GC attributes are usually written with macros; special-case them.
IdentifierInfo *II = attr.isArgIdent(0) ? attr.getArgAsIdent(0)->Ident
@@ -811,7 +811,7 @@ static bool checkOmittedBlockReturnType(Sema &S, Declarator &declarator,
continue;
S.Diag(AL.getLoc(),
diag::warn_block_literal_attributes_on_omitted_return_type)
- << AL.getName();
+ << AL;
ToBeRemoved.push_back(&AL);
}
// Remove bad attributes from the list.
@@ -1290,14 +1290,14 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified)
Result = Context.WCharTy;
else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) {
- S.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec)
+ S.Diag(DS.getTypeSpecSignLoc(), diag::ext_wchar_t_sign_spec)
<< DS.getSpecifierName(DS.getTypeSpecType(),
Context.getPrintingPolicy());
Result = Context.getSignedWCharType();
} else {
assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned &&
"Unknown TSS value");
- S.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec)
+ S.Diag(DS.getTypeSpecSignLoc(), diag::ext_wchar_t_sign_spec)
<< DS.getSpecifierName(DS.getTypeSpecType(),
Context.getPrintingPolicy());
Result = Context.getUnsignedWCharType();
@@ -1633,6 +1633,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
case OpenCLAccessAttr::Keyword_read_only: \
Result = Context.Id##ROTy; \
break; \
+ case OpenCLAccessAttr::SpellingNotCalculated: \
+ llvm_unreachable("Spelling not yet calculated"); \
} \
break;
#include "clang/Basic/OpenCLImageTypes.def"
@@ -1953,7 +1955,8 @@ static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc,
QualifiedFunctionKind QFK) {
// Does T refer to a function type with a cv-qualifier or a ref-qualifier?
const FunctionProtoType *FPT = T->getAs<FunctionProtoType>();
- if (!FPT || (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None))
+ if (!FPT ||
+ (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None))
return false;
S.Diag(Loc, diag::err_compound_qualified_function_type)
@@ -1962,6 +1965,17 @@ static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc,
return true;
}
+bool Sema::CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc) {
+ const FunctionProtoType *FPT = T->getAs<FunctionProtoType>();
+ if (!FPT ||
+ (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None))
+ return false;
+
+ Diag(Loc, diag::err_qualified_function_typeid)
+ << T << getFunctionQualifiersAsString(FPT);
+ return true;
+}
+
/// Build a pointer type.
///
/// \param T The type to which we'll be building a pointer.
@@ -2276,7 +2290,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
}
}
- T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
+ T = Context.getConstantArrayType(T, ConstVal, ArraySize, ASM, Quals);
}
// OpenCL v1.2 s6.9.d: variable length arrays are not supported.
@@ -2461,6 +2475,11 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
checkNonTrivialCUnion(T, Loc, NTCUC_FunctionReturn,
NTCUK_Destruct|NTCUK_Copy);
+ // C++2a [dcl.fct]p12:
+ // A volatile-qualified return type is deprecated
+ if (T.isVolatileQualified() && getLangOpts().CPlusPlus2a)
+ Diag(Loc, diag::warn_deprecated_volatile_return) << T;
+
return false;
}
@@ -2541,6 +2560,11 @@ QualType Sema::BuildFunctionType(QualType T,
Invalid = true;
}
+ // C++2a [dcl.fct]p4:
+ // A parameter with volatile-qualified type is deprecated
+ if (ParamType.isVolatileQualified() && getLangOpts().CPlusPlus2a)
+ Diag(Loc, diag::warn_deprecated_volatile_param) << ParamType;
+
ParamTypes[Idx] = ParamType;
}
@@ -3942,10 +3966,9 @@ static bool IsNoDerefableChunk(DeclaratorChunk Chunk) {
}
template<typename AttrT>
-static AttrT *createSimpleAttr(ASTContext &Ctx, ParsedAttr &Attr) {
- Attr.setUsedAsTypeAttr();
- return ::new (Ctx)
- AttrT(Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex());
+static AttrT *createSimpleAttr(ASTContext &Ctx, ParsedAttr &AL) {
+ AL.setUsedAsTypeAttr();
+ return ::new (Ctx) AttrT(Ctx, AL);
}
static Attr *createNullabilityAttr(ASTContext &Ctx, ParsedAttr &Attr,
@@ -4672,6 +4695,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
S.Diag(DeclType.Loc, diag::err_func_returning_qualified_void) << T;
} else
diagnoseRedundantReturnTypeQualifiers(S, T, D, chunkIndex);
+
+ // C++2a [dcl.fct]p12:
+ // A volatile-qualified return type is deprecated
+ if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus2a)
+ S.Diag(DeclType.Loc, diag::warn_deprecated_volatile_return) << T;
}
// Objective-C ARC ownership qualifiers are ignored on the function
@@ -5151,9 +5179,16 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// C++0x [dcl.constexpr]p9:
// A constexpr specifier used in an object declaration declares the object
// as const.
- if (D.getDeclSpec().hasConstexprSpecifier() && T->isObjectType()) {
+ if (D.getDeclSpec().getConstexprSpecifier() == CSK_constexpr &&
+ T->isObjectType())
T.addConst();
- }
+
+ // C++2a [dcl.fct]p4:
+ // A parameter with volatile-qualified type is deprecated
+ if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus2a &&
+ (D.getContext() == DeclaratorContext::PrototypeContext ||
+ D.getContext() == DeclaratorContext::LambdaExprParameterContext))
+ S.Diag(D.getIdentifierLoc(), diag::warn_deprecated_volatile_param) << T;
// If there was an ellipsis in the declarator, the declaration declares a
// parameter pack whose type may be a pack expansion type.
@@ -5983,9 +6018,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
}
ASTContext &Ctx = S.Context;
- auto *ASAttr = ::new (Ctx) AddressSpaceAttr(
- Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(),
- static_cast<unsigned>(ASIdx));
+ auto *ASAttr =
+ ::new (Ctx) AddressSpaceAttr(Ctx, Attr, static_cast<unsigned>(ASIdx));
// If the expression is not value dependent (not templated), then we can
// apply the address space qualifiers just to the equivalent type.
@@ -6027,36 +6061,6 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
}
}
-/// 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() == attr::ObjCOwnership)
- 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.
///
@@ -6112,8 +6116,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
else if (II->isStr("autoreleasing"))
lifetime = Qualifiers::OCL_Autoreleasing;
else {
- S.Diag(AttrLoc, diag::warn_attribute_type_not_supported)
- << attr.getName() << II;
+ S.Diag(AttrLoc, diag::warn_attribute_type_not_supported) << attr << II;
attr.setInvalid();
return true;
}
@@ -6132,7 +6135,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
if (Qualifiers::ObjCLifetime previousLifetime
= type.getQualifiers().getObjCLifetime()) {
// If it's written directly, that's an error.
- if (hasDirectOwnershipQualifier(type)) {
+ if (S.Context.hasDirectOwnershipQualifier(type)) {
S.Diag(AttrLoc, diag::err_attr_objc_ownership_redundant)
<< type;
return true;
@@ -6155,7 +6158,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
underlyingType.Quals.addObjCLifetime(lifetime);
if (NonObjCPointer) {
- StringRef name = attr.getName()->getName();
+ StringRef name = attr.getAttrName()->getName();
switch (lifetime) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
@@ -6194,9 +6197,8 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
// If we have a valid source location for the attribute, use an
// AttributedType instead.
if (AttrLoc.isValid()) {
- type = state.getAttributedType(::new (S.Context) ObjCOwnershipAttr(
- attr.getRange(), S.Context, II,
- attr.getAttributeSpellingListIndex()),
+ type = state.getAttributedType(::new (S.Context)
+ ObjCOwnershipAttr(S.Context, attr, II),
origType, type);
}
@@ -6288,7 +6290,7 @@ static bool handleObjCGCTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
GCAttr = Qualifiers::Strong;
else {
S.Diag(attr.getLoc(), diag::warn_attribute_type_not_supported)
- << attr.getName() << II;
+ << attr << II;
attr.setInvalid();
return true;
}
@@ -6299,9 +6301,7 @@ static bool handleObjCGCTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
// Make an attributed type to preserve the source information.
if (attr.getLoc().isValid())
type = state.getAttributedType(
- ::new (S.Context) ObjCGCAttr(attr.getRange(), S.Context, II,
- attr.getAttributeSpellingListIndex()),
- origType, type);
+ ::new (S.Context) ObjCGCAttr(S.Context, attr, II), origType, type);
return true;
}
@@ -6473,8 +6473,7 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
// You cannot specify duplicate type attributes, so if the attribute has
// already been applied, flag it.
if (NewAttrKind == CurAttrKind) {
- S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact)
- << PAttr.getName();
+ S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr;
return true;
}
@@ -6743,9 +6742,9 @@ static bool distributeNullabilityTypeAttr(TypeProcessingState &state,
if (chunk.Kind != DeclaratorChunk::MemberPointer) {
diag << FixItHint::CreateRemoval(attr.getLoc())
<< FixItHint::CreateInsertion(
- state.getSema().getPreprocessor()
- .getLocForEndOfToken(chunk.Loc),
- " " + attr.getName()->getName().str() + " ");
+ state.getSema().getPreprocessor().getLocForEndOfToken(
+ chunk.Loc),
+ " " + attr.getAttrName()->getName().str() + " ");
}
moveAttrFromListToList(attr, state.getCurrentAttributes(),
@@ -6823,8 +6822,7 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) {
PcsAttr::PCSType Type;
if (!PcsAttr::ConvertStrToPCSType(Str, Type))
llvm_unreachable("already validated the attribute");
- return ::new (Ctx) PcsAttr(Attr.getRange(), Ctx, Type,
- Attr.getAttributeSpellingListIndex());
+ return ::new (Ctx) PcsAttr(Ctx, Attr, Type);
}
case ParsedAttr::AT_IntelOclBicc:
return createSimpleAttr<IntelOclBiccAttr>(Ctx, Attr);
@@ -7343,7 +7341,7 @@ static void HandleOpenCLAccessAttr(QualType &CurType, const ParsedAttr &Attr,
} else {
llvm_unreachable("unexpected type");
}
- StringRef AttrName = Attr.getName()->getName();
+ StringRef AttrName = Attr.getAttrName()->getName();
if (PrevAccessQual == AttrName.ltrim("_")) {
// Duplicated qualifiers
S.Diag(Attr.getLoc(), diag::warn_duplicate_declspec)
@@ -7390,8 +7388,22 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State,
bool IsPointee =
ChunkIndex > 0 &&
(D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Pointer ||
- D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::BlockPointer ||
- D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Reference);
+ D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Reference ||
+ D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::BlockPointer);
+ // For pointers/references to arrays the next chunk is always an array
+ // followed by any number of parentheses.
+ if (!IsPointee && ChunkIndex > 1) {
+ auto AdjustedCI = ChunkIndex - 1;
+ if (D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Array)
+ AdjustedCI--;
+ // Skip over all parentheses.
+ while (AdjustedCI > 0 &&
+ D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Paren)
+ AdjustedCI--;
+ if (D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Pointer ||
+ D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Reference)
+ IsPointee = true;
+ }
bool IsFuncReturnType =
ChunkIndex > 0 &&
D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Function;
@@ -7526,7 +7538,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
IsTypeAttr
? diag::warn_gcc_ignores_type_attr
: diag::warn_cxx11_gnu_attribute_on_type)
- << attr.getName();
+ << attr;
if (!IsTypeAttr)
continue;
}
@@ -7555,7 +7567,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk)
state.getSema().Diag(attr.getLoc(),
diag::warn_unknown_attribute_ignored)
- << attr.getName();
+ << attr;
break;
case ParsedAttr::IgnoredAttribute:
@@ -7720,7 +7732,9 @@ void Sema::completeExprArrayBound(Expr *E) {
auto *Def = Var->getDefinition();
if (!Def) {
SourceLocation PointOfInstantiation = E->getExprLoc();
- InstantiateVariableDefinition(PointOfInstantiation, Var);
+ runWithSufficientStackSpace(PointOfInstantiation, [&] {
+ InstantiateVariableDefinition(PointOfInstantiation, Var);
+ });
Def = Var->getDefinition();
// If we don't already have a point of instantiation, and we managed
@@ -7947,14 +7961,16 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) {
break;
}
- RD->addAttr(MSInheritanceAttr::CreateImplicit(
- S.getASTContext(), IM,
- /*BestCase=*/S.MSPointerToMemberRepresentationMethod ==
- LangOptions::PPTMK_BestCase,
- S.ImplicitMSInheritanceAttrLoc.isValid()
- ? S.ImplicitMSInheritanceAttrLoc
- : RD->getSourceRange()));
- S.Consumer.AssignInheritanceModel(RD);
+ SourceRange Loc =
+ S.ImplicitMSInheritanceAttrLoc.isValid()
+ ? S.ImplicitMSInheritanceAttrLoc
+ : RD->getSourceRange();
+ RD->addAttr(MSInheritanceAttr::CreateImplicit(
+ S.getASTContext(),
+ /*BestCase=*/S.MSPointerToMemberRepresentationMethod ==
+ LangOptions::PPTMK_BestCase,
+ Loc, AttributeCommonInfo::AS_Microsoft, IM));
+ S.Consumer.AssignInheritanceModel(RD);
}
}
@@ -8058,9 +8074,11 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
} else if (auto *ClassTemplateSpec =
dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) {
- Diagnosed = InstantiateClassTemplateSpecialization(
- Loc, ClassTemplateSpec, TSK_ImplicitInstantiation,
- /*Complain=*/Diagnoser);
+ runWithSufficientStackSpace(Loc, [&] {
+ Diagnosed = InstantiateClassTemplateSpecialization(
+ Loc, ClassTemplateSpec, TSK_ImplicitInstantiation,
+ /*Complain=*/Diagnoser);
+ });
Instantiated = true;
}
} else {
@@ -8071,10 +8089,12 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// This record was instantiated from a class within a template.
if (MSI->getTemplateSpecializationKind() !=
TSK_ExplicitSpecialization) {
- Diagnosed = InstantiateClass(Loc, RD, Pattern,
- getTemplateInstantiationArgs(RD),
- TSK_ImplicitInstantiation,
- /*Complain=*/Diagnoser);
+ runWithSufficientStackSpace(Loc, [&] {
+ Diagnosed = InstantiateClass(Loc, RD, Pattern,
+ getTemplateInstantiationArgs(RD),
+ TSK_ImplicitInstantiation,
+ /*Complain=*/Diagnoser);
+ });
Instantiated = true;
}
}
@@ -8222,20 +8242,28 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
return true;
}
}
- } else if (!RD->hasTrivialDestructor()) {
- // All fields and bases are of literal types, so have trivial destructors.
- // If this class's destructor is non-trivial it must be user-declared.
+ } else if (getLangOpts().CPlusPlus2a ? !RD->hasConstexprDestructor()
+ : !RD->hasTrivialDestructor()) {
+ // All fields and bases are of literal types, so have trivial or constexpr
+ // destructors. If this class's destructor is non-trivial / non-constexpr,
+ // it must be user-declared.
CXXDestructorDecl *Dtor = RD->getDestructor();
assert(Dtor && "class has literal fields and bases but no dtor?");
if (!Dtor)
return true;
- Diag(Dtor->getLocation(), Dtor->isUserProvided() ?
- diag::note_non_literal_user_provided_dtor :
- diag::note_non_literal_nontrivial_dtor) << RD;
- if (!Dtor->isUserProvided())
- SpecialMemberIsTrivial(Dtor, CXXDestructor, TAH_IgnoreTrivialABI,
- /*Diagnose*/true);
+ if (getLangOpts().CPlusPlus2a) {
+ Diag(Dtor->getLocation(), diag::note_non_literal_non_constexpr_dtor)
+ << RD;
+ } else {
+ Diag(Dtor->getLocation(), Dtor->isUserProvided()
+ ? diag::note_non_literal_user_provided_dtor
+ : diag::note_non_literal_nontrivial_dtor)
+ << RD;
+ if (!Dtor->isUserProvided())
+ SpecialMemberIsTrivial(Dtor, CXXDestructor, TAH_IgnoreTrivialABI,
+ /*Diagnose*/ true);
+ }
}
return true;
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 8df18b5c2784..4b3a6708717c 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -795,6 +795,7 @@ public:
QualType RebuildConstantArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt &Size,
+ Expr *SizeExpr,
unsigned IndexTypeQuals,
SourceRange BracketsRange);
@@ -2167,13 +2168,12 @@ public:
ExprResult RebuildDeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
ValueDecl *VD,
const DeclarationNameInfo &NameInfo,
+ NamedDecl *Found,
TemplateArgumentListInfo *TemplateArgs) {
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
-
- // FIXME: loses template args.
-
- return getSema().BuildDeclarationNameExpr(SS, NameInfo, VD);
+ return getSema().BuildDeclarationNameExpr(SS, NameInfo, VD, Found,
+ TemplateArgs);
}
/// Build a new expression in parentheses.
@@ -2353,6 +2353,17 @@ public:
return getSema().BuildBinOp(/*Scope=*/nullptr, OpLoc, Opc, LHS, RHS);
}
+ /// Build a new rewritten operator expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildCXXRewrittenBinaryOperator(
+ SourceLocation OpLoc, BinaryOperatorKind Opcode,
+ const UnresolvedSetImpl &UnqualLookups, Expr *LHS, Expr *RHS) {
+ return getSema().CreateOverloadedBinOp(OpLoc, Opcode, UnqualLookups, LHS,
+ RHS, /*RequiresADL*/false);
+ }
+
/// Build a new conditional operator expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -2417,7 +2428,7 @@ public:
ExprResult RebuildInitList(SourceLocation LBraceLoc,
MultiExprArg Inits,
SourceLocation RBraceLoc) {
- return SemaRef.ActOnInitList(LBraceLoc, Inits, RBraceLoc);
+ return SemaRef.BuildInitList(LBraceLoc, Inits, RBraceLoc);
}
/// Build a new designated initializer expression.
@@ -3019,6 +3030,25 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildConceptSpecializationExpr(NestedNameSpecifierLoc NNS,
+ SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc,
+ NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+ TemplateArgumentListInfo *TALI) {
+ CXXScopeSpec SS;
+ SS.Adopt(NNS);
+ ExprResult Result = getSema().CheckConceptTemplateId(SS, TemplateKWLoc,
+ ConceptNameLoc,
+ FoundDecl,
+ NamedConcept, TALI);
+ if (Result.isInvalid())
+ return ExprError();
+ return Result;
+ }
+
+ /// \brief Build a new Objective-C boxed expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
ExprResult RebuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
return getSema().BuildObjCBoxedExpr(SR, ValueExpr);
}
@@ -3309,16 +3339,14 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- ExprResult RebuildAtomicExpr(SourceLocation BuiltinLoc,
- MultiExprArg SubExprs,
- QualType RetTy,
+ ExprResult RebuildAtomicExpr(SourceLocation BuiltinLoc, MultiExprArg SubExprs,
AtomicExpr::AtomicOp Op,
SourceLocation RParenLoc) {
- // Just create the expression; there is not any interesting semantic
- // analysis here because we can't actually build an AtomicExpr until
- // we are sure it is semantically sound.
- return new (SemaRef.Context) AtomicExpr(BuiltinLoc, SubExprs, RetTy, Op,
- RParenLoc);
+ // Use this for all of the locations, since we don't know the difference
+ // between the call and the expr at this point.
+ SourceRange Range{BuiltinLoc, RParenLoc};
+ return getSema().BuildAtomicExpr(Range, Range, RParenLoc, SubExprs, Op,
+ Sema::AtomicArgumentOrder::AST);
}
private:
@@ -4641,7 +4669,7 @@ TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB,
// Objective-C ARC can add lifetime qualifiers to the type that we're
// referring to.
TLB.TypeWasModifiedSafely(
- Result->getAs<ReferenceType>()->getPointeeTypeAsWritten());
+ Result->castAs<ReferenceType>()->getPointeeTypeAsWritten());
// r-value references can be rebuilt as l-value references.
ReferenceTypeLoc NewTL;
@@ -4729,12 +4757,25 @@ TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB,
if (ElementType.isNull())
return QualType();
+ // Prefer the expression from the TypeLoc; the other may have been uniqued.
+ Expr *OldSize = TL.getSizeExpr();
+ if (!OldSize)
+ OldSize = const_cast<Expr*>(T->getSizeExpr());
+ Expr *NewSize = nullptr;
+ if (OldSize) {
+ EnterExpressionEvaluationContext Unevaluated(
+ SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ NewSize = getDerived().TransformExpr(OldSize).template getAs<Expr>();
+ NewSize = SemaRef.ActOnConstantExpression(NewSize).get();
+ }
+
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() ||
- ElementType != T->getElementType()) {
+ ElementType != T->getElementType() ||
+ (T->getSizeExpr() && NewSize != OldSize)) {
Result = getDerived().RebuildConstantArrayType(ElementType,
T->getSizeModifier(),
- T->getSize(),
+ T->getSize(), NewSize,
T->getIndexTypeCVRQualifiers(),
TL.getBracketsRange());
if (Result.isNull())
@@ -4748,15 +4789,7 @@ TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB,
ArrayTypeLoc NewTL = TLB.push<ArrayTypeLoc>(Result);
NewTL.setLBracketLoc(TL.getLBracketLoc());
NewTL.setRBracketLoc(TL.getRBracketLoc());
-
- Expr *Size = TL.getSizeExpr();
- if (Size) {
- EnterExpressionEvaluationContext Unevaluated(
- SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
- Size = getDerived().TransformExpr(Size).template getAs<Expr>();
- Size = SemaRef.ActOnConstantExpression(Size).get();
- }
- NewTL.setSizeExpr(Size);
+ NewTL.setSizeExpr(NewSize);
return Result;
}
@@ -5928,7 +5961,7 @@ QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB,
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() || ValueType != TL.getValueLoc().getType()) {
- const PipeType *PT = Result->getAs<PipeType>();
+ const PipeType *PT = Result->castAs<PipeType>();
bool isReadPipe = PT->isReadOnly();
Result = getDerived().RebuildPipeType(ValueType, TL.getKWLoc(), isReadPipe);
if (Result.isNull())
@@ -8244,6 +8277,39 @@ StmtResult TreeTransform<Derived>::TransformOMPTaskLoopSimdDirective(
}
template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPMasterTaskLoopDirective(
+ OMPMasterTaskLoopDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_master_taskloop, DirName,
+ nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPMasterTaskLoopSimdDirective(
+ OMPMasterTaskLoopSimdDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_master_taskloop_simd, DirName,
+ nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPParallelMasterTaskLoopDirective(
+ OMPParallelMasterTaskLoopDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(
+ OMPD_parallel_master_taskloop, DirName, nullptr, D->getBeginLoc());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
StmtResult TreeTransform<Derived>::TransformOMPDistributeDirective(
OMPDistributeDirective *D) {
DeclarationNameInfo DirName;
@@ -9204,6 +9270,14 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
if (!ND)
return ExprError();
+ NamedDecl *Found = ND;
+ if (E->getFoundDecl() != E->getDecl()) {
+ Found = cast_or_null<NamedDecl>(
+ getDerived().TransformDecl(E->getLocation(), E->getFoundDecl()));
+ if (!Found)
+ return ExprError();
+ }
+
DeclarationNameInfo NameInfo = E->getNameInfo();
if (NameInfo.getName()) {
NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo);
@@ -9214,6 +9288,7 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
if (!getDerived().AlwaysRebuild() &&
QualifierLoc == E->getQualifierLoc() &&
ND == E->getDecl() &&
+ Found == E->getFoundDecl() &&
NameInfo.getName() == E->getDecl()->getDeclName() &&
!E->hasExplicitTemplateArgs()) {
@@ -9236,7 +9311,7 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
}
return getDerived().RebuildDeclRefExpr(QualifierLoc, ND, NameInfo,
- TemplateArgs);
+ Found, TemplateArgs);
}
template<typename Derived>
@@ -9705,6 +9780,50 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) {
LHS.get(), RHS.get());
}
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformCXXRewrittenBinaryOperator(
+ CXXRewrittenBinaryOperator *E) {
+ CXXRewrittenBinaryOperator::DecomposedForm Decomp = E->getDecomposedForm();
+
+ ExprResult LHS = getDerived().TransformExpr(const_cast<Expr*>(Decomp.LHS));
+ if (LHS.isInvalid())
+ return ExprError();
+
+ ExprResult RHS = getDerived().TransformExpr(const_cast<Expr*>(Decomp.RHS));
+ if (RHS.isInvalid())
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ LHS.get() == Decomp.LHS &&
+ RHS.get() == Decomp.RHS)
+ return E;
+
+ // Extract the already-resolved callee declarations so that we can restrict
+ // ourselves to using them as the unqualified lookup results when rebuilding.
+ UnresolvedSet<2> UnqualLookups;
+ Expr *PossibleBinOps[] = {E->getSemanticForm(),
+ const_cast<Expr *>(Decomp.InnerBinOp)};
+ for (Expr *PossibleBinOp : PossibleBinOps) {
+ auto *Op = dyn_cast<CXXOperatorCallExpr>(PossibleBinOp->IgnoreImplicit());
+ if (!Op)
+ continue;
+ auto *Callee = dyn_cast<DeclRefExpr>(Op->getCallee()->IgnoreImplicit());
+ if (!Callee || isa<CXXMethodDecl>(Callee->getDecl()))
+ continue;
+
+ // Transform the callee in case we built a call to a local extern
+ // declaration.
+ NamedDecl *Found = cast_or_null<NamedDecl>(getDerived().TransformDecl(
+ E->getOperatorLoc(), Callee->getFoundDecl()));
+ if (!Found)
+ return ExprError();
+ UnqualLookups.addDecl(Found);
+ }
+
+ return getDerived().RebuildCXXRewrittenBinaryOperator(
+ E->getOperatorLoc(), Decomp.Opcode, UnqualLookups, LHS.get(), RHS.get());
+}
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCompoundAssignOperator(
@@ -10982,6 +11101,23 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformConceptSpecializationExpr(
+ ConceptSpecializationExpr *E) {
+ const ASTTemplateArgumentListInfo *Old = E->getTemplateArgsAsWritten();
+ TemplateArgumentListInfo TransArgs(Old->LAngleLoc, Old->RAngleLoc);
+ if (getDerived().TransformTemplateArguments(Old->getTemplateArgs(),
+ Old->NumTemplateArgs, TransArgs))
+ return ExprError();
+
+ return getDerived().RebuildConceptSpecializationExpr(
+ E->getNestedNameSpecifierLoc(), E->getTemplateKWLoc(),
+ E->getConceptNameLoc(), E->getFoundDecl(), E->getNamedConcept(),
+ &TransArgs);
+}
+
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
TypeSourceInfo *T = getDerived().TransformType(E->getQueriedTypeSourceInfo());
if (!T)
@@ -11318,10 +11454,14 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
}
}
+ LambdaScopeInfo *LSI = getSema().PushLambdaScope();
+ Sema::FunctionScopeRAII FuncScopeCleanup(getSema());
+
// Transform the template parameters, and add them to the current
// instantiation scope. The null case is handled correctly.
auto TPL = getDerived().TransformTemplateParameterList(
E->getTemplateParameterList());
+ LSI->GLTemplateParameterList = TPL;
// Transform the type of the original lambda's call operator.
// The transformation MUST be done in the CurrentInstantiationScope since
@@ -11348,10 +11488,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
NewCallOpType);
}
- LambdaScopeInfo *LSI = getSema().PushLambdaScope();
- Sema::FunctionScopeRAII FuncScopeCleanup(getSema());
- LSI->GLTemplateParameterList = TPL;
-
// Create the local class that will describe the lambda.
CXXRecordDecl *OldClass = E->getLambdaClass();
CXXRecordDecl *Class
@@ -11361,17 +11497,18 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
E->getCaptureDefault());
getDerived().transformedLocalDecl(OldClass, {Class});
- Optional<std::pair<unsigned, Decl*>> Mangling;
+ Optional<std::tuple<unsigned, bool, Decl *>> Mangling;
if (getDerived().ReplacingOriginal())
- Mangling = std::make_pair(OldClass->getLambdaManglingNumber(),
- OldClass->getLambdaContextDecl());
+ Mangling = std::make_tuple(OldClass->getLambdaManglingNumber(),
+ OldClass->hasKnownLambdaInternalLinkage(),
+ OldClass->getLambdaContextDecl());
// Build the call operator.
CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition(
Class, E->getIntroducerRange(), NewCallOpTSI,
E->getCallOperator()->getEndLoc(),
NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
- E->getCallOperator()->getConstexprKind(), Mangling);
+ E->getCallOperator()->getConstexprKind());
LSI->CallOperator = NewCallOperator;
@@ -11391,6 +11528,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator});
+ // Number the lambda for linkage purposes if necessary.
+ getSema().handleLambdaNumbering(Class, NewCallOperator, Mangling);
+
// Introduce the context of the call operator.
Sema::ContextRAII SavedContext(getSema(), NewCallOperator,
/*NewThisContext*/false);
@@ -11663,7 +11803,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
} else {
OldBase = nullptr;
BaseType = getDerived().TransformType(E->getBaseType());
- ObjectType = BaseType->getAs<PointerType>()->getPointeeType();
+ ObjectType = BaseType->castAs<PointerType>()->getPointeeType();
}
// Transform the first part of the nested-name-specifier that qualifies
@@ -12666,7 +12806,6 @@ TreeTransform<Derived>::TransformAsTypeExpr(AsTypeExpr *E) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) {
- QualType RetTy = getDerived().TransformType(E->getType());
bool ArgumentChanged = false;
SmallVector<Expr*, 8> SubExprs;
SubExprs.reserve(E->getNumSubExprs());
@@ -12679,7 +12818,7 @@ TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) {
return E;
return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), SubExprs,
- RetTy, E->getOp(), E->getRParenLoc());
+ E->getOp(), E->getRParenLoc());
}
//===----------------------------------------------------------------------===//
@@ -12797,9 +12936,10 @@ QualType
TreeTransform<Derived>::RebuildConstantArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
const llvm::APInt &Size,
+ Expr *SizeExpr,
unsigned IndexTypeQuals,
SourceRange BracketsRange) {
- return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, nullptr,
+ return getDerived().RebuildArrayType(ElementType, SizeMod, &Size, SizeExpr,
IndexTypeQuals, BracketsRange);
}
@@ -13183,7 +13323,7 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
if (Base->isTypeDependent() || Destroyed.getIdentifier() ||
(!isArrow && !BaseType->getAs<RecordType>()) ||
(isArrow && BaseType->getAs<PointerType>() &&
- !BaseType->getAs<PointerType>()->getPointeeType()
+ !BaseType->castAs<PointerType>()->getPointeeType()
->template getAs<RecordType>())){
// This pseudo-destructor expression is still a pseudo-destructor.
return SemaRef.BuildPseudoDestructorExpr(
diff --git a/lib/Sema/TypeLocBuilder.cpp b/lib/Sema/TypeLocBuilder.cpp
index b451403544ed..2dcbbd83c691 100644
--- a/lib/Sema/TypeLocBuilder.cpp
+++ b/lib/Sema/TypeLocBuilder.cpp
@@ -51,7 +51,7 @@ void TypeLocBuilder::grow(size_t NewCapacity) {
&Buffer[Index],
Capacity - Index);
- if (Buffer != InlineBuffer.buffer)
+ if (Buffer != InlineBuffer)
delete[] Buffer;
Buffer = NewBuffer;
diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h
index 1e6883926a80..738f731c9fe2 100644
--- a/lib/Sema/TypeLocBuilder.h
+++ b/lib/Sema/TypeLocBuilder.h
@@ -39,18 +39,16 @@ class TypeLocBuilder {
/// The inline buffer.
enum { BufferMaxAlignment = alignof(void *) };
- llvm::AlignedCharArray<BufferMaxAlignment, InlineCapacity> InlineBuffer;
+ alignas(BufferMaxAlignment) char InlineBuffer[InlineCapacity];
unsigned NumBytesAtAlign4, NumBytesAtAlign8;
- public:
+public:
TypeLocBuilder()
- : Buffer(InlineBuffer.buffer), Capacity(InlineCapacity),
- Index(InlineCapacity), NumBytesAtAlign4(0), NumBytesAtAlign8(0)
- {
- }
+ : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity),
+ NumBytesAtAlign4(0), NumBytesAtAlign8(0) {}
~TypeLocBuilder() {
- if (Buffer != InlineBuffer.buffer)
+ if (Buffer != InlineBuffer)
delete[] Buffer;
}
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index aa3477a7d35e..dd06e0582ac5 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -232,6 +232,11 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
case BuiltinType::OCLReserveID:
ID = PREDEF_TYPE_RESERVE_ID_ID;
break;
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case BuiltinType::Id: \
+ ID = PREDEF_TYPE_##Id##_ID; \
+ break;
+#include "clang/Basic/AArch64SVEACLETypes.def"
case BuiltinType::BuiltinFn:
ID = PREDEF_TYPE_BUILTIN_FN;
break;
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 7f2c7f09e8a3..2d3884ebe021 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -1247,6 +1247,12 @@ void ASTReader::Error(unsigned DiagID,
Diag(DiagID) << Arg1 << Arg2;
}
+void ASTReader::Error(unsigned DiagID, StringRef Arg1, StringRef Arg2,
+ unsigned Select) const {
+ if (!Diags.isDiagnosticInFlight())
+ Diag(DiagID) << Arg1 << Arg2 << Select;
+}
+
void ASTReader::Error(llvm::Error &&Err) const {
Error(toString(std::move(Err)));
}
@@ -1514,6 +1520,7 @@ bool ASTReader::ReadSLocEntry(int ID) {
}
SrcMgr::CharacteristicKind
FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
+ // FIXME: The FileID should be created from the FileEntryRef.
FileID FID = SourceMgr.createFileID(File, IncludeLoc, FileCharacter,
ID, BaseOffset + Record[0]);
SrcMgr::FileInfo &FileInfo =
@@ -1522,9 +1529,9 @@ bool ASTReader::ReadSLocEntry(int ID) {
if (Record[3])
FileInfo.setHasLineDirectives();
- const DeclID *FirstDecl = F->FileSortedDecls + Record[6];
unsigned NumFileDecls = Record[7];
if (NumFileDecls && ContextObj) {
+ const DeclID *FirstDecl = F->FileSortedDecls + Record[6];
assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?");
FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl,
NumFileDecls));
@@ -1822,12 +1829,17 @@ bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) {
// Determine whether the actual files are equivalent.
FileManager &FileMgr = Reader.getFileManager();
auto GetFile = [&](const internal_key_type &Key) -> const FileEntry* {
- if (!Key.Imported)
- return FileMgr.getFile(Key.Filename);
+ if (!Key.Imported) {
+ if (auto File = FileMgr.getFile(Key.Filename))
+ return *File;
+ return nullptr;
+ }
std::string Resolved = Key.Filename;
Reader.ResolveImportedPath(M, Resolved);
- return FileMgr.getFile(Resolved);
+ if (auto File = FileMgr.getFile(Resolved))
+ return *File;
+ return nullptr;
};
const FileEntry *FEA = GetFile(a);
@@ -1904,7 +1916,7 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
// FIXME: This is not always the right filename-as-written, but we're not
// going to use this information to rebuild the module, so it doesn't make
// a lot of difference.
- Module::Header H = { key.Filename, FileMgr.getFile(Filename) };
+ Module::Header H = { key.Filename, *FileMgr.getFile(Filename) };
ModMap.addHeader(Mod, H, HeaderRole, /*Imported*/true);
HFI.isModuleHeader |= !(HeaderRole & ModuleMap::TextualHeader);
}
@@ -2235,6 +2247,24 @@ ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) {
R.TopLevelModuleMap = static_cast<bool>(Record[5]);
R.Filename = Blob;
ResolveImportedPath(F, R.Filename);
+
+ Expected<llvm::BitstreamEntry> MaybeEntry = Cursor.advance();
+ if (!MaybeEntry) // FIXME this drops errors on the floor.
+ consumeError(MaybeEntry.takeError());
+ llvm::BitstreamEntry Entry = MaybeEntry.get();
+ assert(Entry.Kind == llvm::BitstreamEntry::Record &&
+ "expected record type for input file hash");
+
+ Record.clear();
+ if (Expected<unsigned> Maybe = Cursor.readRecord(Entry.ID, Record))
+ assert(static_cast<InputFileRecordTypes>(Maybe.get()) == INPUT_FILE_HASH &&
+ "invalid record type for input file hash");
+ else {
+ // FIXME this drops errors on the floor.
+ consumeError(Maybe.takeError());
+ }
+ R.ContentHash = (static_cast<uint64_t>(Record[1]) << 32) |
+ static_cast<uint64_t>(Record[0]);
return R;
}
@@ -2265,8 +2295,12 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
bool Overridden = FI.Overridden;
bool Transient = FI.Transient;
StringRef Filename = FI.Filename;
+ uint64_t StoredContentHash = FI.ContentHash;
+
+ const FileEntry *File = nullptr;
+ if (auto FE = FileMgr.getFile(Filename, /*OpenFile=*/false))
+ File = *FE;
- const FileEntry *File = FileMgr.getFile(Filename, /*OpenFile=*/false);
// If we didn't find the file, resolve it relative to the
// original directory from which this AST file was created.
if (File == nullptr && !F.OriginalDir.empty() && !F.BaseDirectory.empty() &&
@@ -2274,7 +2308,8 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
std::string Resolved = resolveFileRelativeToOriginalDir(
Filename, F.OriginalDir, F.BaseDirectory);
if (!Resolved.empty())
- File = FileMgr.getFile(Resolved);
+ if (auto FE = FileMgr.getFile(Resolved))
+ File = *FE;
}
// For an overridden file, create a virtual file with the stored
@@ -2305,29 +2340,56 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
if ((!Overridden && !Transient) && SM.isFileOverridden(File)) {
if (Complain)
Error(diag::err_fe_pch_file_overridden, Filename);
- // After emitting the diagnostic, recover by disabling the override so
- // that the original file will be used.
- //
- // FIXME: This recovery is just as broken as the original state; there may
- // be another precompiled module that's using the overridden contents, or
- // we might be half way through parsing it. Instead, we should treat the
- // overridden contents as belonging to a separate FileEntry.
- SM.disableFileContentsOverride(File);
- // The FileEntry is a virtual file entry with the size of the contents
- // that would override the original contents. Set it to the original's
- // size/time.
- FileMgr.modifyFileEntry(const_cast<FileEntry*>(File),
- StoredSize, StoredTime);
+
+ // After emitting the diagnostic, bypass the overriding file to recover
+ // (this creates a separate FileEntry).
+ File = SM.bypassFileContentsOverride(*File);
+ if (!File) {
+ F.InputFilesLoaded[ID - 1] = InputFile::getNotFound();
+ return InputFile();
+ }
}
- bool IsOutOfDate = false;
+ enum ModificationType {
+ Size,
+ ModTime,
+ Content,
+ None,
+ };
+ auto HasInputFileChanged = [&]() {
+ if (StoredSize != File->getSize())
+ return ModificationType::Size;
+ if (!DisableValidation && StoredTime &&
+ StoredTime != File->getModificationTime()) {
+ // In case the modification time changes but not the content,
+ // accept the cached file as legit.
+ if (ValidateASTInputFilesContent &&
+ StoredContentHash != static_cast<uint64_t>(llvm::hash_code(-1))) {
+ auto MemBuffOrError = FileMgr.getBufferForFile(File);
+ if (!MemBuffOrError) {
+ if (!Complain)
+ return ModificationType::ModTime;
+ std::string ErrorStr = "could not get buffer for file '";
+ ErrorStr += File->getName();
+ ErrorStr += "'";
+ Error(ErrorStr);
+ return ModificationType::ModTime;
+ }
+ auto ContentHash = hash_value(MemBuffOrError.get()->getBuffer());
+ if (StoredContentHash == static_cast<uint64_t>(ContentHash))
+ return ModificationType::None;
+ return ModificationType::Content;
+ }
+ return ModificationType::ModTime;
+ }
+ return ModificationType::None;
+ };
+
+ bool IsOutOfDate = false;
+ auto FileChange = HasInputFileChanged();
// For an overridden file, there is nothing to validate.
- if (!Overridden && //
- (StoredSize != File->getSize() ||
- (StoredTime && StoredTime != File->getModificationTime() &&
- !DisableValidation)
- )) {
+ if (!Overridden && FileChange != ModificationType::None) {
if (Complain) {
// Build a list of the PCH imports that got us here (in reverse).
SmallVector<ModuleFile *, 4> ImportStack(1, &F);
@@ -2336,13 +2398,17 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
// The top-level PCH is stale.
StringRef TopLevelPCHName(ImportStack.back()->FileName);
- unsigned DiagnosticKind = moduleKindForDiagnostic(ImportStack.back()->Kind);
+ unsigned DiagnosticKind =
+ moduleKindForDiagnostic(ImportStack.back()->Kind);
if (DiagnosticKind == 0)
- Error(diag::err_fe_pch_file_modified, Filename, TopLevelPCHName);
+ Error(diag::err_fe_pch_file_modified, Filename, TopLevelPCHName,
+ (unsigned)FileChange);
else if (DiagnosticKind == 1)
- Error(diag::err_fe_module_file_modified, Filename, TopLevelPCHName);
+ Error(diag::err_fe_module_file_modified, Filename, TopLevelPCHName,
+ (unsigned)FileChange);
else
- Error(diag::err_fe_ast_file_modified, Filename, TopLevelPCHName);
+ Error(diag::err_fe_ast_file_modified, Filename, TopLevelPCHName,
+ (unsigned)FileChange);
// Print the import stack.
if (ImportStack.size() > 1 && !Diags.isDiagnosticInFlight()) {
@@ -2820,9 +2886,8 @@ ASTReader::ReadControlBlock(ModuleFile &F,
// Don't emit module relocation error if we have -fno-validate-pch
if (!PP.getPreprocessorOpts().DisablePCHValidation &&
F.Kind != MK_ExplicitModule && F.Kind != MK_PrebuiltModule) {
- const DirectoryEntry *BuildDir =
- PP.getFileManager().getDirectory(Blob);
- if (!BuildDir || BuildDir != M->Directory) {
+ auto BuildDir = PP.getFileManager().getDirectory(Blob);
+ if (!BuildDir || *BuildDir != M->Directory) {
if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
Diag(diag::err_imported_module_relocated)
<< F.ModuleName << Blob << M->Directory->getName();
@@ -3814,7 +3879,6 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
const FileEntry *ModMap = M ? Map.getModuleMapFileForUniquing(M) : nullptr;
// Don't emit module relocation error if we have -fno-validate-pch
if (!PP.getPreprocessorOpts().DisablePCHValidation && !ModMap) {
- assert(ImportedBy && "top-level import should be verified");
if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) {
if (auto *ASTFE = M ? M->getASTFile() : nullptr) {
// This module was defined by an imported (explicit) module.
@@ -3823,12 +3887,13 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
} else {
// This module was built with a different module map.
Diag(diag::err_imported_module_not_found)
- << F.ModuleName << F.FileName << ImportedBy->FileName
- << F.ModuleMapPath;
+ << F.ModuleName << F.FileName
+ << (ImportedBy ? ImportedBy->FileName : "") << F.ModuleMapPath
+ << !ImportedBy;
// In case it was imported by a PCH, there's a chance the user is
// just missing to include the search path to the directory containing
// the modulemap.
- if (ImportedBy->Kind == MK_PCH)
+ if (ImportedBy && ImportedBy->Kind == MK_PCH)
Diag(diag::note_imported_by_pch_module_not_found)
<< llvm::sys::path::parent_path(F.ModuleMapPath);
}
@@ -3839,14 +3904,16 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
assert(M->Name == F.ModuleName && "found module with different name");
// Check the primary module map file.
- const FileEntry *StoredModMap = FileMgr.getFile(F.ModuleMapPath);
- if (StoredModMap == nullptr || StoredModMap != ModMap) {
+ auto StoredModMap = FileMgr.getFile(F.ModuleMapPath);
+ if (!StoredModMap || *StoredModMap != ModMap) {
assert(ModMap && "found module is missing module map file");
- assert(ImportedBy && "top-level import should be verified");
+ assert((ImportedBy || F.Kind == MK_ImplicitModule) &&
+ "top-level import should be verified");
+ bool NotImported = F.Kind == MK_ImplicitModule && !ImportedBy;
if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
Diag(diag::err_imported_module_modmap_changed)
- << F.ModuleName << ImportedBy->FileName
- << ModMap->getName() << F.ModuleMapPath;
+ << F.ModuleName << (NotImported ? F.FileName : ImportedBy->FileName)
+ << ModMap->getName() << F.ModuleMapPath << NotImported;
return OutOfDate;
}
@@ -3854,14 +3921,13 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F,
for (unsigned I = 0, N = Record[Idx++]; I < N; ++I) {
// FIXME: we should use input files rather than storing names.
std::string Filename = ReadPath(F, Record, Idx);
- const FileEntry *F =
- FileMgr.getFile(Filename, false, false);
- if (F == nullptr) {
+ auto F = FileMgr.getFile(Filename, false, false);
+ if (!F) {
if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
Error("could not find file '" + Filename +"' referenced by AST file");
return OutOfDate;
}
- AdditionalStoredMaps.insert(F);
+ AdditionalStoredMaps.insert(*F);
}
// Check any additional module map files (e.g. module.private.modulemap)
@@ -4035,7 +4101,7 @@ static void updateModuleTimestamp(ModuleFile &MF) {
// Overwrite the timestamp file contents so that file's mtime changes.
std::string TimestampFilename = MF.getTimestampFilename();
std::error_code EC;
- llvm::raw_fd_ostream OS(TimestampFilename, EC, llvm::sys::fs::F_Text);
+ llvm::raw_fd_ostream OS(TimestampFilename, EC, llvm::sys::fs::OF_Text);
if (EC)
return;
OS << "Timestamp file\n";
@@ -5187,6 +5253,8 @@ bool ASTReader::readASTFileControlBlock(
consumeError(MaybeRecordType.takeError());
}
switch ((InputFileRecordTypes)MaybeRecordType.get()) {
+ case INPUT_FILE_HASH:
+ break;
case INPUT_FILE:
bool Overridden = static_cast<bool>(Record[3]);
std::string Filename = Blob;
@@ -5459,10 +5527,10 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
case SUBMODULE_UMBRELLA_HEADER: {
std::string Filename = Blob;
ResolveImportedPath(F, Filename);
- if (auto *Umbrella = PP.getFileManager().getFile(Filename)) {
+ if (auto Umbrella = PP.getFileManager().getFile(Filename)) {
if (!CurrentModule->getUmbrellaHeader())
- ModMap.setUmbrellaHeader(CurrentModule, Umbrella, Blob);
- else if (CurrentModule->getUmbrellaHeader().Entry != Umbrella) {
+ ModMap.setUmbrellaHeader(CurrentModule, *Umbrella, Blob);
+ else if (CurrentModule->getUmbrellaHeader().Entry != *Umbrella) {
if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
Error("mismatched umbrella headers in submodule");
return OutOfDate;
@@ -5492,10 +5560,10 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
case SUBMODULE_UMBRELLA_DIR: {
std::string Dirname = Blob;
ResolveImportedPath(F, Dirname);
- if (auto *Umbrella = PP.getFileManager().getDirectory(Dirname)) {
+ if (auto Umbrella = PP.getFileManager().getDirectory(Dirname)) {
if (!CurrentModule->getUmbrellaDir())
- ModMap.setUmbrellaDir(CurrentModule, Umbrella, Blob);
- else if (CurrentModule->getUmbrellaDir().Entry != Umbrella) {
+ ModMap.setUmbrellaDir(CurrentModule, *Umbrella, Blob);
+ else if (CurrentModule->getUmbrellaDir().Entry != *Umbrella) {
if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
Error("mismatched umbrella directories in submodule");
return OutOfDate;
@@ -5890,7 +5958,8 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
StringRef FullFileName(FullFileNameStart, Blob.size() - Record[0]);
const FileEntry *File = nullptr;
if (!FullFileName.empty())
- File = PP.getFileManager().getFile(FullFileName);
+ if (auto FE = PP.getFileManager().getFile(FullFileName))
+ File = *FE;
// FIXME: Stable encoding
InclusionDirective::InclusionKind Kind
@@ -6373,7 +6442,8 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
unsigned IndexTypeQuals = Record[2];
unsigned Idx = 3;
llvm::APInt Size = ReadAPInt(Record, Idx);
- return Context.getConstantArrayType(ElementType, Size,
+ Expr *SizeExpr = ReadExpr(*Loc.F);
+ return Context.getConstantArrayType(ElementType, Size, SizeExpr,
ASM, IndexTypeQuals);
}
@@ -7413,6 +7483,11 @@ QualType ASTReader::GetType(TypeID ID) {
case PREDEF_TYPE_OMP_ARRAY_SECTION:
T = Context.OMPArraySectionTy;
break;
+#define SVE_TYPE(Name, Id, SingletonId) \
+ case PREDEF_TYPE_##Id##_ID: \
+ T = Context.SingletonId; \
+ break;
+#include "clang/Basic/AArch64SVEACLETypes.def"
}
assert(!T.isNull() && "Unknown predefined type");
@@ -8716,7 +8791,7 @@ void ASTReader::ReadLateParsedTemplates(
/* In loop */) {
FunctionDecl *FD = cast<FunctionDecl>(GetDecl(LateParsedTemplates[Idx++]));
- auto LT = llvm::make_unique<LateParsedTemplate>();
+ auto LT = std::make_unique<LateParsedTemplate>();
LT->D = GetDecl(LateParsedTemplates[Idx++]);
ModuleFile *F = getOwningModuleFile(LT->D);
@@ -9270,9 +9345,11 @@ ASTReader::ReadTemplateParameterList(ModuleFile &F,
while (NumParams--)
Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx));
- // TODO: Concepts
+ bool HasRequiresClause = Record[Idx++];
+ Expr *RequiresClause = HasRequiresClause ? ReadExpr(F) : nullptr;
+
TemplateParameterList *TemplateParams = TemplateParameterList::Create(
- getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, nullptr);
+ getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause);
return TemplateParams;
}
@@ -9718,10 +9795,17 @@ void ASTReader::ReadComments() {
}
}
NextCursor:
- // De-serialized SourceLocations get negative FileIDs for other modules,
- // potentially invalidating the original order. Sort it again.
- llvm::sort(Comments, BeforeThanCompare<RawComment>(SourceMgr));
- Context.Comments.addDeserializedComments(Comments);
+ llvm::DenseMap<FileID, std::map<unsigned, RawComment *>>
+ FileToOffsetToComment;
+ for (RawComment *C : Comments) {
+ SourceLocation CommentLoc = C->getBeginLoc();
+ if (CommentLoc.isValid()) {
+ std::pair<FileID, unsigned> Loc =
+ SourceMgr.getDecomposedLoc(CommentLoc);
+ if (Loc.first.isValid())
+ Context.Comments.OrderedComments[Loc.first].emplace(Loc.second, C);
+ }
+ }
}
}
@@ -12134,7 +12218,7 @@ ASTReader::ASTReader(Preprocessor &PP, InMemoryModuleCache &ModuleCache,
StringRef isysroot, bool DisableValidation,
bool AllowASTWithCompilerErrors,
bool AllowConfigurationMismatch, bool ValidateSystemInputs,
- bool UseGlobalIndex,
+ bool ValidateASTInputFilesContent, bool UseGlobalIndex,
std::unique_ptr<llvm::Timer> ReadTimer)
: Listener(DisableValidation
? cast<ASTReaderListener>(new SimpleASTReaderListener(PP))
@@ -12148,6 +12232,7 @@ ASTReader::ASTReader(Preprocessor &PP, InMemoryModuleCache &ModuleCache,
AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
AllowConfigurationMismatch(AllowConfigurationMismatch),
ValidateSystemInputs(ValidateSystemInputs),
+ ValidateASTInputFilesContent(ValidateASTInputFilesContent),
UseGlobalIndex(UseGlobalIndex), CurrSwitchCaseStmts(&SwitchCaseStmts) {
SourceMgr.setExternalSLocEntrySource(this);
@@ -12184,7 +12269,7 @@ Expected<unsigned> ASTRecordReader::readRecord(llvm::BitstreamCursor &Cursor,
////===----------------------------------------------------------------------===//
OMPClause *OMPClauseReader::readClause() {
- OMPClause *C;
+ OMPClause *C = nullptr;
switch (Record.readInt()) {
case OMPC_if:
C = new (Context) OMPIfClause();
@@ -12385,6 +12470,8 @@ OMPClause *OMPClauseReader::readClause() {
C = OMPAllocateClause::CreateEmpty(Context, Record.readInt());
break;
}
+ assert(C && "Unknown OMPClause type");
+
Visit(C);
C->setLocStart(Record.readSourceLocation());
C->setLocEnd(Record.readSourceLocation());
@@ -12412,6 +12499,7 @@ void OMPClauseReader::VisitOMPIfClause(OMPIfClause *C) {
}
void OMPClauseReader::VisitOMPFinalClause(OMPFinalClause *C) {
+ VisitOMPClauseWithPreInit(C);
C->setCondition(Record.readSubExpr());
C->setLParenLoc(Record.readSourceLocation());
}
@@ -12728,6 +12816,10 @@ void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) {
C->setFinals(Vars);
C->setStep(Record.readSubExpr());
C->setCalcStep(Record.readSubExpr());
+ Vars.clear();
+ for (unsigned I = 0; I != NumVars + 1; ++I)
+ Vars.push_back(Record.readSubExpr());
+ C->setUsedExprs(Vars);
}
void OMPClauseReader::VisitOMPAlignedClause(OMPAlignedClause *C) {
@@ -12904,16 +12996,19 @@ void OMPClauseReader::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) {
}
void OMPClauseReader::VisitOMPPriorityClause(OMPPriorityClause *C) {
+ VisitOMPClauseWithPreInit(C);
C->setPriority(Record.readSubExpr());
C->setLParenLoc(Record.readSourceLocation());
}
void OMPClauseReader::VisitOMPGrainsizeClause(OMPGrainsizeClause *C) {
+ VisitOMPClauseWithPreInit(C);
C->setGrainsize(Record.readSubExpr());
C->setLParenLoc(Record.readSourceLocation());
}
void OMPClauseReader::VisitOMPNumTasksClause(OMPNumTasksClause *C) {
+ VisitOMPClauseWithPreInit(C);
C->setNumTasks(Record.readSubExpr());
C->setLParenLoc(Record.readSourceLocation());
}
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 3cac82ad421c..9aa8c77c6231 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -1390,10 +1390,11 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
if (uint64_t Val = Record.readInt()) {
VD->setInit(Record.readExpr());
- if (Val > 1) { // IsInitKnownICE = 1, IsInitNotICE = 2, IsInitICE = 3
+ if (Val > 1) {
EvaluatedStmt *Eval = VD->ensureEvaluatedStmt();
Eval->CheckedICE = true;
- Eval->IsICE = Val == 3;
+ Eval->IsICE = (Val & 1) != 0;
+ Eval->HasConstantDestruction = (Val & 4) != 0;
}
}
@@ -1655,55 +1656,11 @@ void ASTDeclReader::VisitUnresolvedUsingTypenameDecl(
void ASTDeclReader::ReadCXXDefinitionData(
struct CXXRecordDecl::DefinitionData &Data, const CXXRecordDecl *D) {
+ #define FIELD(Name, Width, Merge) \
+ Data.Name = Record.readInt();
+ #include "clang/AST/CXXRecordDeclDefinitionBits.def"
+
// Note: the caller has deserialized the IsLambda bit already.
- Data.UserDeclaredConstructor = Record.readInt();
- Data.UserDeclaredSpecialMembers = Record.readInt();
- Data.Aggregate = Record.readInt();
- Data.PlainOldData = Record.readInt();
- Data.Empty = Record.readInt();
- Data.Polymorphic = Record.readInt();
- Data.Abstract = Record.readInt();
- Data.IsStandardLayout = Record.readInt();
- Data.IsCXX11StandardLayout = Record.readInt();
- Data.HasBasesWithFields = Record.readInt();
- Data.HasBasesWithNonStaticDataMembers = Record.readInt();
- Data.HasPrivateFields = Record.readInt();
- Data.HasProtectedFields = Record.readInt();
- Data.HasPublicFields = Record.readInt();
- Data.HasMutableFields = Record.readInt();
- Data.HasVariantMembers = Record.readInt();
- Data.HasOnlyCMembers = Record.readInt();
- Data.HasInClassInitializer = Record.readInt();
- Data.HasUninitializedReferenceMember = Record.readInt();
- Data.HasUninitializedFields = Record.readInt();
- Data.HasInheritedConstructor = Record.readInt();
- Data.HasInheritedAssignment = Record.readInt();
- Data.NeedOverloadResolutionForCopyConstructor = Record.readInt();
- Data.NeedOverloadResolutionForMoveConstructor = Record.readInt();
- Data.NeedOverloadResolutionForMoveAssignment = Record.readInt();
- Data.NeedOverloadResolutionForDestructor = Record.readInt();
- Data.DefaultedCopyConstructorIsDeleted = Record.readInt();
- Data.DefaultedMoveConstructorIsDeleted = Record.readInt();
- Data.DefaultedMoveAssignmentIsDeleted = Record.readInt();
- Data.DefaultedDestructorIsDeleted = Record.readInt();
- Data.HasTrivialSpecialMembers = Record.readInt();
- Data.HasTrivialSpecialMembersForCall = Record.readInt();
- Data.DeclaredNonTrivialSpecialMembers = Record.readInt();
- Data.DeclaredNonTrivialSpecialMembersForCall = Record.readInt();
- Data.HasIrrelevantDestructor = Record.readInt();
- Data.HasConstexprNonCopyMoveConstructor = Record.readInt();
- Data.HasDefaultedDefaultConstructor = Record.readInt();
- Data.DefaultedDefaultConstructorIsConstexpr = Record.readInt();
- Data.HasConstexprDefaultConstructor = Record.readInt();
- Data.HasNonLiteralTypeFieldsOrBases = Record.readInt();
- Data.ComputedVisibleConversions = Record.readInt();
- Data.UserProvidedDefaultConstructor = Record.readInt();
- Data.DeclaredSpecialMembers = Record.readInt();
- Data.ImplicitCopyConstructorCanHaveConstParamForVBase = Record.readInt();
- Data.ImplicitCopyConstructorCanHaveConstParamForNonVBase = Record.readInt();
- Data.ImplicitCopyAssignmentHasConstParam = Record.readInt();
- Data.HasDeclaredCopyConstructorWithConstParam = Record.readInt();
- Data.HasDeclaredCopyAssignmentWithConstParam = Record.readInt();
Data.ODRHash = Record.readInt();
Data.HasODRHash = true;
@@ -1718,7 +1675,9 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.VBases = ReadGlobalOffset();
Record.readUnresolvedSet(Data.Conversions);
- Record.readUnresolvedSet(Data.VisibleConversions);
+ Data.ComputedVisibleConversions = Record.readInt();
+ if (Data.ComputedVisibleConversions)
+ Record.readUnresolvedSet(Data.VisibleConversions);
assert(Data.Definition && "Data.Definition should be already set!");
Data.FirstFriend = ReadDeclID();
@@ -1731,6 +1690,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
Lambda.CaptureDefault = Record.readInt();
Lambda.NumCaptures = Record.readInt();
Lambda.NumExplicitCaptures = Record.readInt();
+ Lambda.HasKnownInternalLinkage = Record.readInt();
Lambda.ManglingNumber = Record.readInt();
Lambda.ContextDecl = ReadDeclID();
Lambda.Captures = (Capture *)Reader.getContext().Allocate(
@@ -1791,63 +1751,17 @@ void ASTDeclReader::MergeDefinitionData(
return;
}
- // FIXME: Move this out into a .def file?
bool DetectedOdrViolation = false;
-#define OR_FIELD(Field) DD.Field |= MergeDD.Field;
-#define MATCH_FIELD(Field) \
+
+ #define FIELD(Name, Width, Merge) Merge(Name)
+ #define MERGE_OR(Field) DD.Field |= MergeDD.Field;
+ #define NO_MERGE(Field) \
DetectedOdrViolation |= DD.Field != MergeDD.Field; \
- OR_FIELD(Field)
- MATCH_FIELD(UserDeclaredConstructor)
- MATCH_FIELD(UserDeclaredSpecialMembers)
- MATCH_FIELD(Aggregate)
- MATCH_FIELD(PlainOldData)
- MATCH_FIELD(Empty)
- MATCH_FIELD(Polymorphic)
- MATCH_FIELD(Abstract)
- MATCH_FIELD(IsStandardLayout)
- MATCH_FIELD(IsCXX11StandardLayout)
- MATCH_FIELD(HasBasesWithFields)
- MATCH_FIELD(HasBasesWithNonStaticDataMembers)
- MATCH_FIELD(HasPrivateFields)
- MATCH_FIELD(HasProtectedFields)
- MATCH_FIELD(HasPublicFields)
- MATCH_FIELD(HasMutableFields)
- MATCH_FIELD(HasVariantMembers)
- MATCH_FIELD(HasOnlyCMembers)
- MATCH_FIELD(HasInClassInitializer)
- MATCH_FIELD(HasUninitializedReferenceMember)
- MATCH_FIELD(HasUninitializedFields)
- MATCH_FIELD(HasInheritedConstructor)
- MATCH_FIELD(HasInheritedAssignment)
- MATCH_FIELD(NeedOverloadResolutionForCopyConstructor)
- MATCH_FIELD(NeedOverloadResolutionForMoveConstructor)
- MATCH_FIELD(NeedOverloadResolutionForMoveAssignment)
- MATCH_FIELD(NeedOverloadResolutionForDestructor)
- MATCH_FIELD(DefaultedCopyConstructorIsDeleted)
- MATCH_FIELD(DefaultedMoveConstructorIsDeleted)
- MATCH_FIELD(DefaultedMoveAssignmentIsDeleted)
- MATCH_FIELD(DefaultedDestructorIsDeleted)
- OR_FIELD(HasTrivialSpecialMembers)
- OR_FIELD(HasTrivialSpecialMembersForCall)
- OR_FIELD(DeclaredNonTrivialSpecialMembers)
- OR_FIELD(DeclaredNonTrivialSpecialMembersForCall)
- MATCH_FIELD(HasIrrelevantDestructor)
- OR_FIELD(HasConstexprNonCopyMoveConstructor)
- OR_FIELD(HasDefaultedDefaultConstructor)
- MATCH_FIELD(DefaultedDefaultConstructorIsConstexpr)
- OR_FIELD(HasConstexprDefaultConstructor)
- MATCH_FIELD(HasNonLiteralTypeFieldsOrBases)
- // ComputedVisibleConversions is handled below.
- MATCH_FIELD(UserProvidedDefaultConstructor)
- OR_FIELD(DeclaredSpecialMembers)
- MATCH_FIELD(ImplicitCopyConstructorCanHaveConstParamForVBase)
- MATCH_FIELD(ImplicitCopyConstructorCanHaveConstParamForNonVBase)
- MATCH_FIELD(ImplicitCopyAssignmentHasConstParam)
- OR_FIELD(HasDeclaredCopyConstructorWithConstParam)
- OR_FIELD(HasDeclaredCopyAssignmentWithConstParam)
- MATCH_FIELD(IsLambda)
-#undef OR_FIELD
-#undef MATCH_FIELD
+ MERGE_OR(Field)
+ #include "clang/AST/CXXRecordDeclDefinitionBits.def"
+ NO_MERGE(IsLambda)
+ #undef NO_MERGE
+ #undef MERGE_OR
if (DD.NumBases != MergeDD.NumBases || DD.NumVBases != MergeDD.NumVBases)
DetectedOdrViolation = true;
@@ -2087,7 +2001,6 @@ DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
DeclID PatternID = ReadDeclID();
auto *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID));
TemplateParameterList *TemplateParams = Record.readTemplateParameterList();
- // FIXME handle associated constraints
D->init(TemplatedDecl, TemplateParams);
return PatternID;
@@ -2253,7 +2166,8 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D) {
RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
- D->TemplateParams = Record.readTemplateParameterList();
+ TemplateParameterList *Params = Record.readTemplateParameterList();
+ D->TemplateParams = Params;
D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
// These are read/set from/to the first declaration.
@@ -2355,7 +2269,8 @@ void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
VarTemplatePartialSpecializationDecl *D) {
RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
- D->TemplateParams = Record.readTemplateParameterList();
+ TemplateParameterList *Params = Record.readTemplateParameterList();
+ D->TemplateParams = Params;
D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
// These are read/set from/to the first declaration.
@@ -2371,6 +2286,7 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
D->setDeclaredWithTypename(Record.readInt());
+ // TODO: Concepts: Immediately introduced constraint
if (Record.readInt())
D->setDefaultArgument(GetTypeSourceInfo());
}
@@ -2748,6 +2664,10 @@ public:
return Reader->ReadSourceRange(*F, Record, Idx);
}
+ SourceLocation readSourceLocation() {
+ return Reader->ReadSourceLocation(*F, Record, Idx);
+ }
+
Expr *readExpr() { return Reader->ReadExpr(*F); }
std::string readString() {
@@ -2783,9 +2703,20 @@ Attr *ASTReader::ReadAttr(ModuleFile &M, const RecordData &Rec,
// Kind is stored as a 1-based integer because 0 is used to indicate a null
// Attr pointer.
auto Kind = static_cast<attr::Kind>(V - 1);
- SourceRange Range = Record.readSourceRange();
ASTContext &Context = getContext();
+ IdentifierInfo *AttrName = Record.getIdentifierInfo();
+ IdentifierInfo *ScopeName = Record.getIdentifierInfo();
+ SourceRange AttrRange = Record.readSourceRange();
+ SourceLocation ScopeLoc = Record.readSourceLocation();
+ unsigned ParsedKind = Record.readInt();
+ unsigned Syntax = Record.readInt();
+ unsigned SpellingIndex = Record.readInt();
+
+ AttributeCommonInfo Info(AttrName, ScopeName, AttrRange, ScopeLoc,
+ AttributeCommonInfo::Kind(ParsedKind),
+ AttributeCommonInfo::Syntax(Syntax), SpellingIndex);
+
#include "clang/Serialization/AttrPCHRead.inc"
assert(New && "Unable to decode attribute?");
@@ -4551,8 +4482,9 @@ void ASTDeclReader::UpdateDecl(Decl *D,
break;
case UPD_DECL_MARKED_OPENMP_THREADPRIVATE:
- D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(Reader.getContext(),
- ReadSourceRange()));
+ D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(
+ Reader.getContext(), ReadSourceRange(),
+ AttributeCommonInfo::AS_Pragma));
break;
case UPD_DECL_MARKED_OPENMP_ALLOCATE: {
@@ -4561,7 +4493,8 @@ void ASTDeclReader::UpdateDecl(Decl *D,
Expr *Allocator = Record.readExpr();
SourceRange SR = ReadSourceRange();
D->addAttr(OMPAllocateDeclAttr::CreateImplicit(
- Reader.getContext(), AllocatorKind, Allocator, SR));
+ Reader.getContext(), AllocatorKind, Allocator, SR,
+ AttributeCommonInfo::AS_Pragma));
break;
}
@@ -4574,12 +4507,16 @@ void ASTDeclReader::UpdateDecl(Decl *D,
break;
}
- case UPD_DECL_MARKED_OPENMP_DECLARETARGET:
+ case UPD_DECL_MARKED_OPENMP_DECLARETARGET: {
+ OMPDeclareTargetDeclAttr::MapTypeTy MapType =
+ static_cast<OMPDeclareTargetDeclAttr::MapTypeTy>(Record.readInt());
+ OMPDeclareTargetDeclAttr::DevTypeTy DevType =
+ static_cast<OMPDeclareTargetDeclAttr::DevTypeTy>(Record.readInt());
D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(
- Reader.getContext(),
- static_cast<OMPDeclareTargetDeclAttr::MapTypeTy>(Record.readInt()),
- ReadSourceRange()));
+ Reader.getContext(), MapType, DevType, ReadSourceRange(),
+ AttributeCommonInfo::AS_Pragma));
break;
+ }
case UPD_ADDED_ATTR_TO_RECORD:
AttrVec Attrs;
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index afaaa543bb27..a275e0c30579 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -734,6 +734,24 @@ void ASTStmtReader::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
E->setRParenLoc(ReadSourceLocation());
}
+void ASTStmtReader::VisitConceptSpecializationExpr(
+ ConceptSpecializationExpr *E) {
+ VisitExpr(E);
+ unsigned NumTemplateArgs = Record.readInt();
+ E->NestedNameSpec = Record.readNestedNameSpecifierLoc();
+ E->TemplateKWLoc = Record.readSourceLocation();
+ E->ConceptNameLoc = Record.readSourceLocation();
+ E->FoundDecl = ReadDeclAs<NamedDecl>();
+ E->NamedConcept.setPointer(ReadDeclAs<ConceptDecl>());
+ const ASTTemplateArgumentListInfo *ArgsAsWritten =
+ Record.readASTTemplateArgumentListInfo();
+ llvm::SmallVector<TemplateArgument, 4> Args;
+ for (unsigned I = 0; I < NumTemplateArgs; ++I)
+ Args.push_back(Record.readTemplateArgument());
+ E->setTemplateArguments(ArgsAsWritten, Args);
+ E->NamedConcept.setInt(Record.readInt() == 1);
+}
+
void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
VisitExpr(E);
E->setLHS(Record.readSubExpr());
@@ -1422,6 +1440,13 @@ void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
E->Range = Record.readSourceRange();
}
+void ASTStmtReader::VisitCXXRewrittenBinaryOperator(
+ CXXRewrittenBinaryOperator *E) {
+ VisitExpr(E);
+ E->CXXRewrittenBinaryOperatorBits.IsReversed = Record.readInt();
+ E->SemanticForm = Record.readSubExpr();
+}
+
void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
VisitExpr(E);
@@ -2060,6 +2085,18 @@ void ASTStmtReader::VisitOMPLoopDirective(OMPLoopDirective *D) {
for (unsigned i = 0; i < CollapsedNum; ++i)
Sub.push_back(Record.readSubExpr());
D->setFinals(Sub);
+ Sub.clear();
+ for (unsigned i = 0; i < CollapsedNum; ++i)
+ Sub.push_back(Record.readSubExpr());
+ D->setDependentCounters(Sub);
+ Sub.clear();
+ for (unsigned i = 0; i < CollapsedNum; ++i)
+ Sub.push_back(Record.readSubExpr());
+ D->setDependentInits(Sub);
+ Sub.clear();
+ for (unsigned i = 0; i < CollapsedNum; ++i)
+ Sub.push_back(Record.readSubExpr());
+ D->setFinalsConditions(Sub);
}
void ASTStmtReader::VisitOMPParallelDirective(OMPParallelDirective *D) {
@@ -2264,6 +2301,21 @@ void ASTStmtReader::VisitOMPTaskLoopSimdDirective(OMPTaskLoopSimdDirective *D) {
VisitOMPLoopDirective(D);
}
+void ASTStmtReader::VisitOMPMasterTaskLoopDirective(
+ OMPMasterTaskLoopDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void ASTStmtReader::VisitOMPMasterTaskLoopSimdDirective(
+ OMPMasterTaskLoopSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
+void ASTStmtReader::VisitOMPParallelMasterTaskLoopDirective(
+ OMPParallelMasterTaskLoopDirective *D) {
+ VisitOMPLoopDirective(D);
+}
+
void ASTStmtReader::VisitOMPDistributeDirective(OMPDistributeDirective *D) {
VisitOMPLoopDirective(D);
}
@@ -3055,6 +3107,30 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
}
+ case STMT_OMP_MASTER_TASKLOOP_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPMasterTaskLoopDirective::CreateEmpty(Context, NumClauses,
+ CollapsedNum, Empty);
+ break;
+ }
+
+ case STMT_OMP_MASTER_TASKLOOP_SIMD_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPMasterTaskLoopSimdDirective::CreateEmpty(Context, NumClauses,
+ CollapsedNum, Empty);
+ break;
+ }
+
+ case STMT_OMP_PARALLEL_MASTER_TASKLOOP_DIRECTIVE: {
+ unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
+ unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
+ S = OMPParallelMasterTaskLoopDirective::CreateEmpty(Context, NumClauses,
+ CollapsedNum, Empty);
+ break;
+ }
+
case STMT_OMP_DISTRIBUTE_DIRECTIVE: {
unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1];
@@ -3183,6 +3259,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], Empty);
break;
+ case EXPR_CXX_REWRITTEN_BINARY_OPERATOR:
+ S = new (Context) CXXRewrittenBinaryOperator(Empty);
+ break;
+
case EXPR_CXX_CONSTRUCT:
S = CXXConstructExpr::CreateEmpty(
Context,
@@ -3452,6 +3532,12 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
case EXPR_DEPENDENT_COAWAIT:
S = new (Context) DependentCoawaitExpr(Empty);
break;
+
+ case EXPR_CONCEPT_SPECIALIZATION:
+ unsigned numTemplateArgs = Record[ASTStmtReader::NumExprFields];
+ S = ConceptSpecializationExpr::Create(Context, Empty, numTemplateArgs);
+ break;
+
}
// We hit a STMT_STOP, so we're done with this expression.
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 10946f9b0d98..28affedbbb30 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -166,7 +166,7 @@ namespace clang {
#define TYPE(Class, Base) \
case Type::Class: Visit##Class##Type(cast<Class##Type>(T)); break;
#define ABSTRACT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
}
}
}
@@ -177,7 +177,7 @@ namespace clang {
#define TYPE(Class, Base) void Visit##Class##Type(const Class##Type *T);
#define ABSTRACT_TYPE(Class, Base)
-#include "clang/AST/TypeNodes.def"
+#include "clang/AST/TypeNodes.inc"
};
} // namespace clang
@@ -238,6 +238,7 @@ void ASTTypeWriter::VisitArrayType(const ArrayType *T) {
void ASTTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) {
VisitArrayType(T);
Record.AddAPInt(T->getSize());
+ Record.AddStmt(const_cast<Expr*>(T->getSizeExpr()));
Code = TYPE_CONSTANT_ARRAY;
}
@@ -1023,6 +1024,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(STMT_CXX_FOR_RANGE);
RECORD(EXPR_CXX_OPERATOR_CALL);
RECORD(EXPR_CXX_MEMBER_CALL);
+ RECORD(EXPR_CXX_REWRITTEN_BINARY_OPERATOR);
RECORD(EXPR_CXX_CONSTRUCT);
RECORD(EXPR_CXX_TEMPORARY_OBJECT);
RECORD(EXPR_CXX_STATIC_CAST);
@@ -1098,6 +1100,7 @@ void ASTWriter::WriteBlockInfoBlock() {
BLOCK(INPUT_FILES_BLOCK);
RECORD(INPUT_FILE);
+ RECORD(INPUT_FILE_HASH);
// AST Top-Level Block.
BLOCK(AST_BLOCK);
@@ -1763,6 +1766,7 @@ struct InputFileEntry {
bool IsTransient;
bool BufferOverridden;
bool IsTopLevelModuleMap;
+ uint32_t ContentHash[2];
};
} // namespace
@@ -1786,6 +1790,13 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned IFAbbrevCode = Stream.EmitAbbrev(std::move(IFAbbrev));
+ // Create input file hash abbreviation.
+ auto IFHAbbrev = std::make_shared<BitCodeAbbrev>();
+ IFHAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE_HASH));
+ IFHAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ IFHAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ unsigned IFHAbbrevCode = Stream.EmitAbbrev(std::move(IFHAbbrev));
+
// Get all ContentCache objects for files, sorted by whether the file is a
// system one or not. System files go at the back, users files at the front.
std::deque<InputFileEntry> SortedFiles;
@@ -1804,12 +1815,31 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
InputFileEntry Entry;
Entry.File = Cache->OrigEntry;
- Entry.IsSystemFile = Cache->IsSystemFile;
+ Entry.IsSystemFile = isSystem(File.getFileCharacteristic());
Entry.IsTransient = Cache->IsTransient;
Entry.BufferOverridden = Cache->BufferOverridden;
Entry.IsTopLevelModuleMap = isModuleMap(File.getFileCharacteristic()) &&
File.getIncludeLoc().isInvalid();
- if (Cache->IsSystemFile)
+
+ auto ContentHash = hash_code(-1);
+ if (PP->getHeaderSearchInfo()
+ .getHeaderSearchOpts()
+ .ValidateASTInputFilesContent) {
+ auto *MemBuff = Cache->getRawBuffer();
+ if (MemBuff)
+ ContentHash = hash_value(MemBuff->getBuffer());
+ else
+ // FIXME: The path should be taken from the FileEntryRef.
+ PP->Diag(SourceLocation(), diag::err_module_unable_to_hash_content)
+ << Entry.File->getName();
+ }
+ auto CH = llvm::APInt(64, ContentHash);
+ Entry.ContentHash[0] =
+ static_cast<uint32_t>(CH.getLoBits(32).getZExtValue());
+ Entry.ContentHash[1] =
+ static_cast<uint32_t>(CH.getHiBits(32).getZExtValue());
+
+ if (Entry.IsSystemFile)
SortedFiles.push_back(Entry);
else
SortedFiles.push_front(Entry);
@@ -1833,16 +1863,26 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
// Emit size/modification time for this file.
// And whether this file was overridden.
- RecordData::value_type Record[] = {
- INPUT_FILE,
- InputFileOffsets.size(),
- (uint64_t)Entry.File->getSize(),
- (uint64_t)getTimestampForOutput(Entry.File),
- Entry.BufferOverridden,
- Entry.IsTransient,
- Entry.IsTopLevelModuleMap};
+ {
+ RecordData::value_type Record[] = {
+ INPUT_FILE,
+ InputFileOffsets.size(),
+ (uint64_t)Entry.File->getSize(),
+ (uint64_t)getTimestampForOutput(Entry.File),
+ Entry.BufferOverridden,
+ Entry.IsTransient,
+ Entry.IsTopLevelModuleMap};
+
+ // FIXME: The path should be taken from the FileEntryRef.
+ EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName());
+ }
- EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName());
+ // Emit content hash for this file.
+ {
+ RecordData::value_type Record[] = {INPUT_FILE_HASH, Entry.ContentHash[0],
+ Entry.ContentHash[1]};
+ Stream.EmitRecordWithAbbrev(IFHAbbrevCode, Record);
+ }
}
Stream.ExitBlock();
@@ -2314,8 +2354,8 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// We add one to the size so that we capture the trailing NULL
// that is required by llvm::MemoryBuffer::getMemBuffer (on
// the reader side).
- const llvm::MemoryBuffer *Buffer
- = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
+ const llvm::MemoryBuffer *Buffer =
+ Content->getBuffer(PP.getDiagnostics(), PP.getFileManager());
StringRef Name = Buffer->getBufferIdentifier();
Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record,
StringRef(Name.data(), Name.size() + 1));
@@ -2329,7 +2369,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// Include the implicit terminating null character in the on-disk buffer
// if we're writing it uncompressed.
const llvm::MemoryBuffer *Buffer =
- Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());
+ Content->getBuffer(PP.getDiagnostics(), PP.getFileManager());
StringRef Blob(Buffer->getBufferStart(), Buffer->getBufferSize() + 1);
emitBlob(Stream, Blob, SLocBufferBlobCompressedAbbrv,
SLocBufferBlobAbbrv);
@@ -2506,7 +2546,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
MacroIdentifiers.push_back(Id.second);
// Sort the set of macro definitions that need to be serialized by the
// name of the macro, to provide a stable ordering.
- llvm::sort(MacroIdentifiers, llvm::less_ptr<IdentifierInfo>());
+ llvm::sort(MacroIdentifiers, llvm::deref<std::less<>>());
// Emit the macro directives as a list and associate the offset with the
// identifier they belong to.
@@ -3266,15 +3306,17 @@ void ASTWriter::WriteComments() {
auto _ = llvm::make_scope_exit([this] { Stream.ExitBlock(); });
if (!PP->getPreprocessorOpts().WriteCommentListToPCH)
return;
- ArrayRef<RawComment *> RawComments = Context->Comments.getComments();
RecordData Record;
- for (const auto *I : RawComments) {
- Record.clear();
- AddSourceRange(I->getSourceRange(), Record);
- Record.push_back(I->getKind());
- Record.push_back(I->isTrailingComment());
- Record.push_back(I->isAlmostTrailingComment());
- Stream.EmitRecord(COMMENTS_RAW_COMMENT, Record);
+ for (const auto &FO : Context->Comments.OrderedComments) {
+ for (const auto &OC : FO.second) {
+ const RawComment *I = OC.second;
+ Record.clear();
+ AddSourceRange(I->getSourceRange(), Record);
+ Record.push_back(I->getKind());
+ Record.push_back(I->isTrailingComment());
+ Record.push_back(I->isAlmostTrailingComment());
+ Stream.EmitRecord(COMMENTS_RAW_COMMENT, Record);
+ }
}
}
@@ -3746,7 +3788,7 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
IIs.push_back(ID.second);
// Sort the identifiers lexicographically before getting them references so
// that their order is stable.
- llvm::sort(IIs, llvm::less_ptr<IdentifierInfo>());
+ llvm::sort(IIs, llvm::deref<std::less<>>());
for (const IdentifierInfo *II : IIs)
if (Trait.isInterestingNonMacroIdentifier(II))
getIdentifierRef(II);
@@ -4519,7 +4561,14 @@ void ASTRecordWriter::AddAttr(const Attr *A) {
if (!A)
return Record.push_back(0);
Record.push_back(A->getKind() + 1); // FIXME: stable encoding, target attrs
+
+ Record.AddIdentifierRef(A->getAttrName());
+ Record.AddIdentifierRef(A->getScopeName());
Record.AddSourceRange(A->getRange());
+ Record.AddSourceLocation(A->getScopeLoc());
+ Record.push_back(A->getParsedKind());
+ Record.push_back(A->getSyntax());
+ Record.push_back(A->getAttributeSpellingListIndexRaw());
#include "clang/Serialization/AttrPCHWrite.inc"
}
@@ -4922,7 +4971,7 @@ ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
IIs.push_back(II);
}
// Sort the identifiers to visit based on their name.
- llvm::sort(IIs, llvm::less_ptr<IdentifierInfo>());
+ llvm::sort(IIs, llvm::deref<std::less<>>());
for (const IdentifierInfo *II : IIs) {
for (IdentifierResolver::iterator D = SemaRef.IdResolver.begin(II),
DEnd = SemaRef.IdResolver.end();
@@ -6022,10 +6071,16 @@ void ASTRecordWriter::AddTemplateParameterList(
AddSourceLocation(TemplateParams->getTemplateLoc());
AddSourceLocation(TemplateParams->getLAngleLoc());
AddSourceLocation(TemplateParams->getRAngleLoc());
- // TODO: Concepts
+
Record->push_back(TemplateParams->size());
for (const auto &P : *TemplateParams)
AddDeclRef(P);
+ if (const Expr *RequiresClause = TemplateParams->getRequiresClause()) {
+ Record->push_back(true);
+ AddStmt(const_cast<Expr*>(RequiresClause));
+ } else {
+ Record->push_back(false);
+ }
}
/// Emit a template argument list.
@@ -6130,54 +6185,10 @@ void ASTRecordWriter::AddCXXCtorInitializers(
void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
auto &Data = D->data();
Record->push_back(Data.IsLambda);
- Record->push_back(Data.UserDeclaredConstructor);
- Record->push_back(Data.UserDeclaredSpecialMembers);
- Record->push_back(Data.Aggregate);
- Record->push_back(Data.PlainOldData);
- Record->push_back(Data.Empty);
- Record->push_back(Data.Polymorphic);
- Record->push_back(Data.Abstract);
- Record->push_back(Data.IsStandardLayout);
- Record->push_back(Data.IsCXX11StandardLayout);
- Record->push_back(Data.HasBasesWithFields);
- Record->push_back(Data.HasBasesWithNonStaticDataMembers);
- Record->push_back(Data.HasPrivateFields);
- Record->push_back(Data.HasProtectedFields);
- Record->push_back(Data.HasPublicFields);
- Record->push_back(Data.HasMutableFields);
- Record->push_back(Data.HasVariantMembers);
- Record->push_back(Data.HasOnlyCMembers);
- Record->push_back(Data.HasInClassInitializer);
- Record->push_back(Data.HasUninitializedReferenceMember);
- Record->push_back(Data.HasUninitializedFields);
- Record->push_back(Data.HasInheritedConstructor);
- Record->push_back(Data.HasInheritedAssignment);
- Record->push_back(Data.NeedOverloadResolutionForCopyConstructor);
- Record->push_back(Data.NeedOverloadResolutionForMoveConstructor);
- Record->push_back(Data.NeedOverloadResolutionForMoveAssignment);
- Record->push_back(Data.NeedOverloadResolutionForDestructor);
- Record->push_back(Data.DefaultedCopyConstructorIsDeleted);
- Record->push_back(Data.DefaultedMoveConstructorIsDeleted);
- Record->push_back(Data.DefaultedMoveAssignmentIsDeleted);
- Record->push_back(Data.DefaultedDestructorIsDeleted);
- Record->push_back(Data.HasTrivialSpecialMembers);
- Record->push_back(Data.HasTrivialSpecialMembersForCall);
- Record->push_back(Data.DeclaredNonTrivialSpecialMembers);
- Record->push_back(Data.DeclaredNonTrivialSpecialMembersForCall);
- Record->push_back(Data.HasIrrelevantDestructor);
- Record->push_back(Data.HasConstexprNonCopyMoveConstructor);
- Record->push_back(Data.HasDefaultedDefaultConstructor);
- Record->push_back(Data.DefaultedDefaultConstructorIsConstexpr);
- Record->push_back(Data.HasConstexprDefaultConstructor);
- Record->push_back(Data.HasNonLiteralTypeFieldsOrBases);
- Record->push_back(Data.ComputedVisibleConversions);
- Record->push_back(Data.UserProvidedDefaultConstructor);
- Record->push_back(Data.DeclaredSpecialMembers);
- Record->push_back(Data.ImplicitCopyConstructorCanHaveConstParamForVBase);
- Record->push_back(Data.ImplicitCopyConstructorCanHaveConstParamForNonVBase);
- Record->push_back(Data.ImplicitCopyAssignmentHasConstParam);
- Record->push_back(Data.HasDeclaredCopyConstructorWithConstParam);
- Record->push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
+
+ #define FIELD(Name, Width, Merge) \
+ Record->push_back(Data.Name);
+ #include "clang/AST/CXXRecordDeclDefinitionBits.def"
// getODRHash will compute the ODRHash if it has not been previously computed.
Record->push_back(D->getODRHash());
@@ -6199,7 +6210,9 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
AddCXXBaseSpecifiers(Data.vbases());
AddUnresolvedSet(Data.Conversions.get(*Writer->Context));
- AddUnresolvedSet(Data.VisibleConversions.get(*Writer->Context));
+ Record->push_back(Data.ComputedVisibleConversions);
+ if (Data.ComputedVisibleConversions)
+ AddUnresolvedSet(Data.VisibleConversions.get(*Writer->Context));
// Data.Definition is the owning decl, no need to write it.
AddDeclRef(D->getFirstFriend());
@@ -6211,6 +6224,7 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
Record->push_back(Lambda.CaptureDefault);
Record->push_back(Lambda.NumCaptures);
Record->push_back(Lambda.NumExplicitCaptures);
+ Record->push_back(Lambda.HasKnownInternalLinkage);
Record->push_back(Lambda.ManglingNumber);
AddDeclRef(D->getLambdaContextDecl());
AddTypeSourceInfo(Lambda.MethodTyInfo);
@@ -6627,6 +6641,7 @@ void OMPClauseWriter::VisitOMPIfClause(OMPIfClause *C) {
}
void OMPClauseWriter::VisitOMPFinalClause(OMPFinalClause *C) {
+ VisitOMPClauseWithPreInit(C);
Record.AddStmt(C->getCondition());
Record.AddSourceLocation(C->getLParenLoc());
}
@@ -6846,6 +6861,8 @@ void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) {
}
Record.AddStmt(C->getStep());
Record.AddStmt(C->getCalcStep());
+ for (auto *VE : C->used_expressions())
+ Record.AddStmt(VE);
}
void OMPClauseWriter::VisitOMPAlignedClause(OMPAlignedClause *C) {
@@ -6962,16 +6979,19 @@ void OMPClauseWriter::VisitOMPThreadLimitClause(OMPThreadLimitClause *C) {
}
void OMPClauseWriter::VisitOMPPriorityClause(OMPPriorityClause *C) {
+ VisitOMPClauseWithPreInit(C);
Record.AddStmt(C->getPriority());
Record.AddSourceLocation(C->getLParenLoc());
}
void OMPClauseWriter::VisitOMPGrainsizeClause(OMPGrainsizeClause *C) {
+ VisitOMPClauseWithPreInit(C);
Record.AddStmt(C->getGrainsize());
Record.AddSourceLocation(C->getLParenLoc());
}
void OMPClauseWriter::VisitOMPNumTasksClause(OMPNumTasksClause *C) {
+ VisitOMPClauseWithPreInit(C);
Record.AddStmt(C->getNumTasks());
Record.AddSourceLocation(C->getLParenLoc());
}
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index b71315505de9..039b57f88e73 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -968,7 +968,14 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(D->getLinkageInternal());
if (D->getInit()) {
- Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2));
+ if (!D->isInitKnownICE())
+ Record.push_back(1);
+ else {
+ Record.push_back(
+ 2 |
+ (D->isInitICE() ? 1 : 0) |
+ (D->ensureEvaluatedStmt()->HasConstantDestruction ? 4 : 0));
+ }
Record.AddStmt(D->getInit());
} else {
Record.push_back(0);
@@ -1601,7 +1608,7 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
VisitTypeDecl(D);
Record.push_back(D->wasDeclaredWithTypename());
-
+ // TODO: Concepts - constrained parameters.
bool OwnsDefaultArg = D->hasDefaultArgument() &&
!D->defaultArgumentWasInherited();
Record.push_back(OwnsDefaultArg);
@@ -1631,6 +1638,7 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
Code = serialization::DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK;
} else {
+ // TODO: Concepts - constrained parameters.
// Rest of NonTypeTemplateParmDecl.
Record.push_back(D->isParameterPack());
bool OwnsDefaultArg = D->hasDefaultArgument() &&
@@ -1660,6 +1668,7 @@ void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
Record.AddTemplateParameterList(D->getExpansionTemplateParameters(I));
Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK;
} else {
+ // TODO: Concepts - constrained parameters.
// Rest of TemplateTemplateParmDecl.
Record.push_back(D->isParameterPack());
bool OwnsDefaultArg = D->hasDefaultArgument() &&
@@ -2140,7 +2149,7 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // ImplicitParamKind
Abv->Add(BitCodeAbbrevOp(0)); // EscapingByref
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // IsInitICE (local)
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // IsInitICE (local)
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // VarKind (local enum)
// Type Source Info
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 4fbcbaabe74b..c39d4d39bcdf 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -388,6 +388,24 @@ void ASTStmtWriter::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) {
Code = serialization::EXPR_DEPENDENT_COAWAIT;
}
+void ASTStmtWriter::VisitConceptSpecializationExpr(
+ ConceptSpecializationExpr *E) {
+ VisitExpr(E);
+ ArrayRef<TemplateArgument> TemplateArgs = E->getTemplateArguments();
+ Record.push_back(TemplateArgs.size());
+ Record.AddNestedNameSpecifierLoc(E->getNestedNameSpecifierLoc());
+ Record.AddSourceLocation(E->getTemplateKWLoc());
+ Record.AddSourceLocation(E->getConceptNameLoc());
+ Record.AddDeclRef(E->getFoundDecl());
+ Record.AddDeclRef(E->getNamedConcept());
+ Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten());
+ for (const TemplateArgument &Arg : TemplateArgs)
+ Record.AddTemplateArgument(Arg);
+ Record.push_back(E->isSatisfied());
+ Code = serialization::EXPR_CONCEPT_SPECIALIZATION;
+}
+
+
void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
VisitStmt(S);
// NumCaptures
@@ -1357,6 +1375,14 @@ void ASTStmtWriter::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
Code = serialization::EXPR_CXX_MEMBER_CALL;
}
+void ASTStmtWriter::VisitCXXRewrittenBinaryOperator(
+ CXXRewrittenBinaryOperator *E) {
+ VisitExpr(E);
+ Record.push_back(E->isReversed());
+ Record.AddStmt(E->getSemanticForm());
+ Code = serialization::EXPR_CXX_REWRITTEN_BINARY_OPERATOR;
+}
+
void ASTStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
VisitExpr(E);
@@ -1995,6 +2021,12 @@ void ASTStmtWriter::VisitOMPLoopDirective(OMPLoopDirective *D) {
for (auto I : D->finals()) {
Record.AddStmt(I);
}
+ for (Stmt *S : D->dependent_counters())
+ Record.AddStmt(S);
+ for (Stmt *S : D->dependent_inits())
+ Record.AddStmt(S);
+ for (Stmt *S : D->finals_conditions())
+ Record.AddStmt(S);
}
void ASTStmtWriter::VisitOMPParallelDirective(OMPParallelDirective *D) {
@@ -2217,6 +2249,24 @@ void ASTStmtWriter::VisitOMPTaskLoopSimdDirective(OMPTaskLoopSimdDirective *D) {
Code = serialization::STMT_OMP_TASKLOOP_SIMD_DIRECTIVE;
}
+void ASTStmtWriter::VisitOMPMasterTaskLoopDirective(
+ OMPMasterTaskLoopDirective *D) {
+ VisitOMPLoopDirective(D);
+ Code = serialization::STMT_OMP_MASTER_TASKLOOP_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPMasterTaskLoopSimdDirective(
+ OMPMasterTaskLoopSimdDirective *D) {
+ VisitOMPLoopDirective(D);
+ Code = serialization::STMT_OMP_MASTER_TASKLOOP_SIMD_DIRECTIVE;
+}
+
+void ASTStmtWriter::VisitOMPParallelMasterTaskLoopDirective(
+ OMPParallelMasterTaskLoopDirective *D) {
+ VisitOMPLoopDirective(D);
+ Code = serialization::STMT_OMP_PARALLEL_MASTER_TASKLOOP_DIRECTIVE;
+}
+
void ASTStmtWriter::VisitOMPDistributeDirective(OMPDistributeDirective *D) {
VisitOMPLoopDirective(D);
Code = serialization::STMT_OMP_DISTRIBUTE_DIRECTIVE;
diff --git a/lib/Serialization/GlobalModuleIndex.cpp b/lib/Serialization/GlobalModuleIndex.cpp
index 2db8f830c46d..54ab17681ee9 100644
--- a/lib/Serialization/GlobalModuleIndex.cpp
+++ b/lib/Serialization/GlobalModuleIndex.cpp
@@ -10,7 +10,6 @@
//
//===----------------------------------------------------------------------===//
-
#include "ASTReaderInternals.h"
#include "clang/Basic/FileManager.h"
#include "clang/Lex/HeaderSearch.h"
@@ -21,10 +20,12 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Bitstream/BitstreamReader.h"
#include "llvm/Bitstream/BitstreamWriter.h"
#include "llvm/Support/DJB.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/LockFileManager.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/OnDiskHashTable.h"
@@ -657,7 +658,7 @@ llvm::Error GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
Idx += Length;
// Find the imported module file.
- const FileEntry *DependsOnFile
+ auto DependsOnFile
= FileMgr.getFile(ImportedFile, /*OpenFile=*/false,
/*CacheFailure=*/false);
@@ -669,11 +670,11 @@ llvm::Error GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
// Save the information in ImportedModuleFileInfo so we can verify after
// loading all pcms.
ImportedModuleFiles.insert(std::make_pair(
- DependsOnFile, ImportedModuleFileInfo(StoredSize, StoredModTime,
- StoredSignature)));
+ *DependsOnFile, ImportedModuleFileInfo(StoredSize, StoredModTime,
+ StoredSignature)));
// Record the dependency.
- unsigned DependsOnID = getModuleFileInfo(DependsOnFile).ID;
+ unsigned DependsOnID = getModuleFileInfo(*DependsOnFile).ID;
getModuleFileInfo(File).Dependencies.push_back(DependsOnID);
}
@@ -894,12 +895,12 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr,
}
// If we can't find the module file, skip it.
- const FileEntry *ModuleFile = FileMgr.getFile(D->path());
+ auto ModuleFile = FileMgr.getFile(D->path());
if (!ModuleFile)
continue;
// Load this module file.
- if (llvm::Error Err = Builder.loadModuleFile(ModuleFile))
+ if (llvm::Error Err = Builder.loadModuleFile(*ModuleFile))
return Err;
}
@@ -912,37 +913,9 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr,
"failed writing index");
}
- // Write the global index file to a temporary file.
- llvm::SmallString<128> IndexTmpPath;
- int TmpFD;
- if (llvm::sys::fs::createUniqueFile(IndexPath + "-%%%%%%%%", TmpFD,
- IndexTmpPath))
- return llvm::createStringError(std::errc::io_error,
- "failed creating unique file");
-
- // Open the temporary global index file for output.
- llvm::raw_fd_ostream Out(TmpFD, true);
- if (Out.has_error())
- return llvm::createStringError(Out.error(), "failed outputting to stream");
-
- // Write the index.
- Out.write(OutputBuffer.data(), OutputBuffer.size());
- Out.close();
- if (Out.has_error())
- return llvm::createStringError(Out.error(), "failed writing to stream");
-
- // Remove the old index file. It isn't relevant any more.
- llvm::sys::fs::remove(IndexPath);
-
- // Rename the newly-written index file to the proper name.
- if (std::error_code Err = llvm::sys::fs::rename(IndexTmpPath, IndexPath)) {
- // Remove the file on failure, don't check whether removal succeeded.
- llvm::sys::fs::remove(IndexTmpPath);
- return llvm::createStringError(Err, "failed renaming file \"%s\" to \"%s\"",
- IndexTmpPath.c_str(), IndexPath.c_str());
- }
-
- return llvm::Error::success();
+ return llvm::writeFileAtomically(
+ (IndexPath + "-%%%%%%%%").str(), IndexPath,
+ llvm::StringRef(OutputBuffer.data(), OutputBuffer.size()));
}
namespace {
diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp
index 6ae0c4f57551..4b9f20fca4f8 100644
--- a/lib/Serialization/ModuleManager.cpp
+++ b/lib/Serialization/ModuleManager.cpp
@@ -42,10 +42,10 @@ using namespace clang;
using namespace serialization;
ModuleFile *ModuleManager::lookupByFileName(StringRef Name) const {
- const FileEntry *Entry = FileMgr.getFile(Name, /*OpenFile=*/false,
- /*CacheFailure=*/false);
+ auto Entry = FileMgr.getFile(Name, /*OpenFile=*/false,
+ /*CacheFailure=*/false);
if (Entry)
- return lookup(Entry);
+ return lookup(*Entry);
return nullptr;
}
@@ -68,9 +68,11 @@ ModuleFile *ModuleManager::lookup(const FileEntry *File) const {
std::unique_ptr<llvm::MemoryBuffer>
ModuleManager::lookupBuffer(StringRef Name) {
- const FileEntry *Entry = FileMgr.getFile(Name, /*OpenFile=*/false,
- /*CacheFailure=*/false);
- return std::move(InMemoryBuffers[Entry]);
+ auto Entry = FileMgr.getFile(Name, /*OpenFile=*/false,
+ /*CacheFailure=*/false);
+ if (!Entry)
+ return nullptr;
+ return std::move(InMemoryBuffers[*Entry]);
}
static bool checkSignature(ASTFileSignature Signature,
@@ -142,7 +144,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
}
// Allocate a new module.
- auto NewModule = llvm::make_unique<ModuleFile>(Type, Generation);
+ auto NewModule = std::make_unique<ModuleFile>(Type, Generation);
NewModule->Index = Chain.size();
NewModule->FileName = FileName.str();
NewModule->File = Entry;
@@ -183,9 +185,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
Buf = llvm::MemoryBuffer::getSTDIN();
} else {
// Get a buffer of the file and close the file descriptor when done.
- Buf = FileMgr.getBufferForFile(NewModule->File,
- /*isVolatile=*/false,
- /*ShouldClose=*/true);
+ Buf = FileMgr.getBufferForFile(NewModule->File, /*isVolatile=*/false);
}
if (!Buf) {
@@ -202,13 +202,8 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
// Read the signature eagerly now so that we can check it. Avoid calling
// ReadSignature unless there's something to check though.
if (ExpectedSignature && checkSignature(ReadSignature(NewModule->Data),
- ExpectedSignature, ErrorStr)) {
- // Try to remove the buffer. If it can't be removed, then it was already
- // validated by this process.
- if (!getModuleCache().tryToDropPCM(NewModule->FileName))
- FileMgr.invalidateCache(NewModule->File);
+ ExpectedSignature, ErrorStr))
return OutOfDate;
- }
// We're keeping this module. Store it everywhere.
Module = Modules[Entry] = NewModule.get();
@@ -447,9 +442,13 @@ bool ModuleManager::lookupModuleFile(StringRef FileName,
// Open the file immediately to ensure there is no race between stat'ing and
// opening the file.
- File = FileMgr.getFile(FileName, /*OpenFile=*/true, /*CacheFailure=*/false);
- if (!File)
+ auto FileOrErr = FileMgr.getFile(FileName, /*OpenFile=*/true,
+ /*CacheFailure=*/false);
+ if (!FileOrErr) {
+ File = nullptr;
return false;
+ }
+ File = *FileOrErr;
if ((ExpectedSize && ExpectedSize != File->getSize()) ||
(ExpectedModTime && ExpectedModTime != File->getModificationTime()))
diff --git a/lib/Serialization/PCHContainerOperations.cpp b/lib/Serialization/PCHContainerOperations.cpp
index 00063d64f3f2..d4990fce2d99 100644
--- a/lib/Serialization/PCHContainerOperations.cpp
+++ b/lib/Serialization/PCHContainerOperations.cpp
@@ -54,7 +54,7 @@ std::unique_ptr<ASTConsumer> RawPCHContainerWriter::CreatePCHContainerGenerator(
CompilerInstance &CI, const std::string &MainFileName,
const std::string &OutputFileName, std::unique_ptr<llvm::raw_pwrite_stream> OS,
std::shared_ptr<PCHBuffer> Buffer) const {
- return llvm::make_unique<RawPCHContainerGenerator>(std::move(OS), Buffer);
+ return std::make_unique<RawPCHContainerGenerator>(std::move(OS), Buffer);
}
StringRef
@@ -63,6 +63,6 @@ RawPCHContainerReader::ExtractPCH(llvm::MemoryBufferRef Buffer) const {
}
PCHContainerOperations::PCHContainerOperations() {
- registerWriter(llvm::make_unique<RawPCHContainerWriter>());
- registerReader(llvm::make_unique<RawPCHContainerReader>());
+ registerWriter(std::make_unique<RawPCHContainerWriter>());
+ registerReader(std::make_unique<RawPCHContainerReader>());
}
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
index 58017acb4a24..8d4793e0802f 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
@@ -75,7 +75,8 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
// reference is outside the range.
// Generate a report for this bug.
- auto report = llvm::make_unique<BugReport>(*BT, BT->getDescription(), N);
+ auto report =
+ std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
report->addRange(LoadS->getSourceRange());
C.emitReport(std::move(report));
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 3bf8a1836b19..8f3bf138cae4 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -208,7 +208,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
SVal ByteOffset = rawOffset.getByteOffset();
if (isTainted(state, ByteOffset)) {
reportOOB(checkerContext, state_exceedsUpperBound, OOB_Tainted,
- llvm::make_unique<TaintBugVisitor>(ByteOffset));
+ std::make_unique<TaintBugVisitor>(ByteOffset));
return;
}
} else if (state_exceedsUpperBound) {
@@ -256,7 +256,7 @@ void ArrayBoundCheckerV2::reportOOB(
break;
}
- auto BR = llvm::make_unique<BugReport>(*BT, os.str(), errorNode);
+ auto BR = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), errorNode);
BR->addVisitor(std::move(Visitor));
checkerContext.emitReport(std::move(BR));
}
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index e3fb4c3eb523..325952fe4ed4 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -211,7 +211,7 @@ void NilArgChecker::generateBugReport(ExplodedNode *N,
if (!BT)
BT.reset(new APIMisuse(this, "nil argument"));
- auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
R->addRange(Range);
bugreporter::trackExpressionValue(N, E, *R);
C.emitReport(std::move(R));
@@ -520,7 +520,7 @@ void CFNumberChecker::checkPreStmt(const CallExpr *CE,
if (!BT)
BT.reset(new APIMisuse(this, "Bad use of CFNumber APIs"));
- auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
+ auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
report->addRange(CE->getArg(2)->getSourceRange());
C.emitReport(std::move(report));
}
@@ -575,7 +575,7 @@ void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
OS << "Null pointer argument in call to "
<< cast<FunctionDecl>(Call.getDecl())->getName();
- auto report = llvm::make_unique<BugReport>(BT, OS.str(), N);
+ auto report = std::make_unique<PathSensitiveBugReport>(BT, OS.str(), N);
report->addRange(Call.getArgSourceRange(0));
bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *report);
C.emitReport(std::move(report));
@@ -635,7 +635,7 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
"of class '" << Class->getName()
<< "' and not the class directly";
- auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
+ auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
report->addRange(msg.getSourceRange());
C.emitReport(std::move(report));
}
@@ -788,7 +788,8 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
ArgTy.print(os, C.getLangOpts());
os << "'";
- auto R = llvm::make_unique<BugReport>(*BT, os.str(), errorNode.getValue());
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(),
+ errorNode.getValue());
R->addRange(msg.getArgSourceRange(I));
C.emitReport(std::move(R));
}
diff --git a/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
index 009160fc9815..0eb3c3d1d0e6 100644
--- a/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
@@ -126,7 +126,7 @@ bool BlockInCriticalSectionChecker::isLockFunction(const CallEvent &Call) const
bool BlockInCriticalSectionChecker::isUnlockFunction(const CallEvent &Call) const {
if (const auto *Dtor = dyn_cast<CXXDestructorCall>(&Call)) {
- const auto *DRecordDecl = dyn_cast<CXXRecordDecl>(Dtor->getDecl()->getParent());
+ const auto *DRecordDecl = cast<CXXRecordDecl>(Dtor->getDecl()->getParent());
auto IdentifierInfo = DRecordDecl->getIdentifier();
if (IdentifierInfo == IILockGuard || IdentifierInfo == IIUniqueLock)
return true;
@@ -173,7 +173,8 @@ void BlockInCriticalSectionChecker::reportBlockInCritSection(
llvm::raw_string_ostream os(msg);
os << "Call to blocking function '" << Call.getCalleeIdentifier()->getName()
<< "' inside of critical section";
- auto R = llvm::make_unique<BugReport>(*BlockInCritSectionBugType, os.str(), ErrNode);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BlockInCritSectionBugType,
+ os.str(), ErrNode);
R->addRange(Call.getSourceRange());
R->markInteresting(BlockDescSym);
C.emitReport(std::move(R));
diff --git a/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
index de8763c1b7b5..1423b9c39b26 100644
--- a/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
@@ -34,7 +34,9 @@ void BoolAssignmentChecker::emitReport(ProgramStateRef state,
if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
if (!BT)
BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value"));
- C.emitReport(llvm::make_unique<BugReport>(*BT, BT->getDescription(), N));
+
+ C.emitReport(
+ std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N));
}
}
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 44f4530781a8..503c451670b8 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -48,10 +48,10 @@ public:
DefaultBool CheckCStringBufferOverlap;
DefaultBool CheckCStringNotNullTerm;
- CheckName CheckNameCStringNullArg;
- CheckName CheckNameCStringOutOfBounds;
- CheckName CheckNameCStringBufferOverlap;
- CheckName CheckNameCStringNotNullTerm;
+ CheckerNameRef CheckNameCStringNullArg;
+ CheckerNameRef CheckNameCStringOutOfBounds;
+ CheckerNameRef CheckNameCStringBufferOverlap;
+ CheckerNameRef CheckNameCStringNotNullTerm;
};
CStringChecksFilter Filter;
@@ -198,7 +198,8 @@ public:
ProgramStateRef checkNonNull(CheckerContext &C,
ProgramStateRef state,
const Expr *S,
- SVal l) const;
+ SVal l,
+ unsigned IdxOfArg) const;
ProgramStateRef CheckLocation(CheckerContext &C,
ProgramStateRef state,
const Expr *S,
@@ -277,7 +278,8 @@ CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V,
ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
ProgramStateRef state,
- const Expr *S, SVal l) const {
+ const Expr *S, SVal l,
+ unsigned IdxOfArg) const {
// If a previous check has failed, propagate the failure.
if (!state)
return nullptr;
@@ -288,11 +290,13 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
if (stateNull && !stateNonNull) {
if (Filter.CheckCStringNullArg) {
SmallString<80> buf;
- llvm::raw_svector_ostream os(buf);
+ llvm::raw_svector_ostream OS(buf);
assert(CurrentFunctionDescription);
- os << "Null pointer argument in call to " << CurrentFunctionDescription;
+ OS << "Null pointer argument in call to " << CurrentFunctionDescription
+ << ' ' << IdxOfArg << llvm::getOrdinalSuffix(IdxOfArg)
+ << " parameter";
- emitNullArgBug(C, stateNull, S, os.str());
+ emitNullArgBug(C, stateNull, S, OS.str());
}
return nullptr;
}
@@ -384,7 +388,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
// Check that the first buffer is non-null.
SVal BufVal = C.getSVal(FirstBuf);
- state = checkNonNull(C, state, FirstBuf, BufVal);
+ state = checkNonNull(C, state, FirstBuf, BufVal, 1);
if (!state)
return nullptr;
@@ -424,7 +428,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
// If there's a second buffer, check it as well.
if (SecondBuf) {
BufVal = state->getSVal(SecondBuf, LCtx);
- state = checkNonNull(C, state, SecondBuf, BufVal);
+ state = checkNonNull(C, state, SecondBuf, BufVal, 2);
if (!state)
return nullptr;
@@ -566,7 +570,7 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state,
categories::UnixAPI, "Improper arguments"));
// Generate a report for this bug.
- auto report = llvm::make_unique<BugReport>(
+ auto report = std::make_unique<PathSensitiveBugReport>(
*BT_Overlap, "Arguments must not be overlapping buffers", N);
report->addRange(First->getSourceRange());
report->addRange(Second->getSourceRange());
@@ -583,7 +587,7 @@ void CStringChecker::emitNullArgBug(CheckerContext &C, ProgramStateRef State,
"Null pointer argument in call to byte string function"));
BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Null.get());
- auto Report = llvm::make_unique<BugReport>(*BT, WarningMsg, N);
+ auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N);
Report->addRange(S->getSourceRange());
if (const auto *Ex = dyn_cast<Expr>(S))
bugreporter::trackExpressionValue(N, Ex, *Report);
@@ -607,7 +611,7 @@ void CStringChecker::emitOutOfBoundsBug(CheckerContext &C,
// FIXME: It would be nice to eventually make this diagnostic more clear,
// e.g., by referencing the original declaration or by saying *why* this
// reference is outside the range.
- auto Report = llvm::make_unique<BugReport>(*BT, WarningMsg, N);
+ auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N);
Report->addRange(S->getSourceRange());
C.emitReport(std::move(Report));
}
@@ -622,7 +626,8 @@ void CStringChecker::emitNotCStringBug(CheckerContext &C, ProgramStateRef State,
Filter.CheckNameCStringNotNullTerm, categories::UnixAPI,
"Argument is not a null-terminated string."));
- auto Report = llvm::make_unique<BugReport>(*BT_NotCString, WarningMsg, N);
+ auto Report =
+ std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N);
Report->addRange(S->getSourceRange());
C.emitReport(std::move(Report));
@@ -644,7 +649,8 @@ void CStringChecker::emitAdditionOverflowBug(CheckerContext &C,
"This expression will create a string whose length is too big to "
"be represented as a size_t";
- auto Report = llvm::make_unique<BugReport>(*BT_NotCString, WarningMsg, N);
+ auto Report =
+ std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N);
C.emitReport(std::move(Report));
}
}
@@ -1163,7 +1169,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
// Ensure the destination is not null. If it is NULL there will be a
// NULL pointer dereference.
- state = checkNonNull(C, state, Dest, destVal);
+ state = checkNonNull(C, state, Dest, destVal, 1);
if (!state)
return;
@@ -1172,7 +1178,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
// Ensure the source is not null. If it is NULL there will be a
// NULL pointer dereference.
- state = checkNonNull(C, state, Source, srcVal);
+ state = checkNonNull(C, state, Source, srcVal, 2);
if (!state)
return;
@@ -1383,7 +1389,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
const Expr *Arg = CE->getArg(0);
SVal ArgVal = state->getSVal(Arg, LCtx);
- state = checkNonNull(C, state, Arg, ArgVal);
+ state = checkNonNull(C, state, Arg, ArgVal, 1);
if (!state)
return;
@@ -1541,14 +1547,14 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
const Expr *Dst = CE->getArg(0);
SVal DstVal = state->getSVal(Dst, LCtx);
- state = checkNonNull(C, state, Dst, DstVal);
+ state = checkNonNull(C, state, Dst, DstVal, 1);
if (!state)
return;
// Check that the source is non-null.
const Expr *srcExpr = CE->getArg(1);
SVal srcVal = state->getSVal(srcExpr, LCtx);
- state = checkNonNull(C, state, srcExpr, srcVal);
+ state = checkNonNull(C, state, srcExpr, srcVal, 2);
if (!state)
return;
@@ -1904,14 +1910,14 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
// Check that the first string is non-null
const Expr *s1 = CE->getArg(0);
SVal s1Val = state->getSVal(s1, LCtx);
- state = checkNonNull(C, state, s1, s1Val);
+ state = checkNonNull(C, state, s1, s1Val, 1);
if (!state)
return;
// Check that the second string is non-null.
const Expr *s2 = CE->getArg(1);
SVal s2Val = state->getSVal(s2, LCtx);
- state = checkNonNull(C, state, s2, s2Val);
+ state = checkNonNull(C, state, s2, s2Val, 2);
if (!state)
return;
@@ -2038,14 +2044,14 @@ void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const {
// Check that the search string pointer is non-null (though it may point to
// a null string).
SVal SearchStrVal = State->getSVal(SearchStrPtr, LCtx);
- State = checkNonNull(C, State, SearchStrPtr, SearchStrVal);
+ State = checkNonNull(C, State, SearchStrPtr, SearchStrVal, 1);
if (!State)
return;
// Check that the delimiter string is non-null.
const Expr *DelimStr = CE->getArg(1);
SVal DelimStrVal = State->getSVal(DelimStr, LCtx);
- State = checkNonNull(C, State, DelimStr, DelimStrVal);
+ State = checkNonNull(C, State, DelimStr, DelimStrVal, 2);
if (!State)
return;
@@ -2148,7 +2154,7 @@ void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const {
// Ensure the memory area is not null.
// If it is NULL there will be a NULL pointer dereference.
- State = checkNonNull(C, StateNonZeroSize, Mem, MemVal);
+ State = checkNonNull(C, StateNonZeroSize, Mem, MemVal, 1);
if (!State)
return;
@@ -2195,7 +2201,7 @@ void CStringChecker::evalBzero(CheckerContext &C, const CallExpr *CE) const {
// Ensure the memory area is not null.
// If it is NULL there will be a NULL pointer dereference.
- State = checkNonNull(C, StateNonZeroSize, Mem, MemVal);
+ State = checkNonNull(C, StateNonZeroSize, Mem, MemVal, 1);
if (!State)
return;
@@ -2403,14 +2409,12 @@ bool ento::shouldRegisterCStringModeling(const LangOptions &LO) {
void ento::register##name(CheckerManager &mgr) { \
CStringChecker *checker = mgr.getChecker<CStringChecker>(); \
checker->Filter.Check##name = true; \
- checker->Filter.CheckName##name = mgr.getCurrentCheckName(); \
+ checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \
} \
\
- bool ento::shouldRegister##name(const LangOptions &LO) { \
- return true; \
- }
+ bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
- REGISTER_CHECKER(CStringNullArg)
- REGISTER_CHECKER(CStringOutOfBounds)
- REGISTER_CHECKER(CStringBufferOverlap)
+REGISTER_CHECKER(CStringNullArg)
+REGISTER_CHECKER(CStringOutOfBounds)
+REGISTER_CHECKER(CStringBufferOverlap)
REGISTER_CHECKER(CStringNotNullTerm)
diff --git a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
index b828ac059236..d84fcc69a492 100644
--- a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
@@ -156,14 +156,21 @@ bool WalkAST::containsBadStrlcpyStrlcatPattern(const CallExpr *CE) {
const Expr *DstArg = CE->getArg(0);
const Expr *LenArg = CE->getArg(2);
- const auto *DstArgDecl = dyn_cast<DeclRefExpr>(DstArg->IgnoreParenImpCasts());
- const auto *LenArgDecl = dyn_cast<DeclRefExpr>(LenArg->IgnoreParenLValueCasts());
+ const auto *DstArgDRE = dyn_cast<DeclRefExpr>(DstArg->IgnoreParenImpCasts());
+ const auto *LenArgDRE =
+ dyn_cast<DeclRefExpr>(LenArg->IgnoreParenLValueCasts());
uint64_t DstOff = 0;
if (isSizeof(LenArg, DstArg))
return false;
+
// - size_t dstlen = sizeof(dst)
- if (LenArgDecl) {
- const auto *LenArgVal = dyn_cast<VarDecl>(LenArgDecl->getDecl());
+ if (LenArgDRE) {
+ const auto *LenArgVal = dyn_cast<VarDecl>(LenArgDRE->getDecl());
+ // If it's an EnumConstantDecl instead, then we're missing out on something.
+ if (!LenArgVal) {
+ assert(isa<EnumConstantDecl>(LenArgDRE->getDecl()));
+ return false;
+ }
if (LenArgVal->getInit())
LenArg = LenArgVal->getInit();
}
@@ -177,9 +184,10 @@ bool WalkAST::containsBadStrlcpyStrlcatPattern(const CallExpr *CE) {
// Case when there is pointer arithmetic on the destination buffer
// especially when we offset from the base decreasing the
// buffer length accordingly.
- if (!DstArgDecl) {
- if (const auto *BE = dyn_cast<BinaryOperator>(DstArg->IgnoreParenImpCasts())) {
- DstArgDecl = dyn_cast<DeclRefExpr>(BE->getLHS()->IgnoreParenImpCasts());
+ if (!DstArgDRE) {
+ if (const auto *BE =
+ dyn_cast<BinaryOperator>(DstArg->IgnoreParenImpCasts())) {
+ DstArgDRE = dyn_cast<DeclRefExpr>(BE->getLHS()->IgnoreParenImpCasts());
if (BE->getOpcode() == BO_Add) {
if ((IL = dyn_cast<IntegerLiteral>(BE->getRHS()->IgnoreParenImpCasts()))) {
DstOff = IL->getValue().getZExtValue();
@@ -187,8 +195,9 @@ bool WalkAST::containsBadStrlcpyStrlcatPattern(const CallExpr *CE) {
}
}
}
- if (DstArgDecl) {
- if (const auto *Buffer = dyn_cast<ConstantArrayType>(DstArgDecl->getType())) {
+ if (DstArgDRE) {
+ if (const auto *Buffer =
+ dyn_cast<ConstantArrayType>(DstArgDRE->getType())) {
ASTContext &C = BR.getContext();
uint64_t BufferLen = C.getTypeSize(Buffer) / 8;
auto RemainingBufferLen = BufferLen - DstOff;
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 5a7eba0760fe..2fcb765cd4ee 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -49,7 +49,7 @@ class CallAndMessageChecker
public:
DefaultBool Check_CallAndMessageUnInitRefArg;
- CheckName CheckName_CallAndMessageUnInitRefArg;
+ CheckerNameRef CheckName_CallAndMessageUnInitRefArg;
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
@@ -95,7 +95,7 @@ void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
if (!N)
return;
- auto R = llvm::make_unique<BugReport>(*BT, BT->getName(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
if (BadE) {
R->addRange(BadE->getSourceRange());
if (BadE->isGLValue())
@@ -175,7 +175,7 @@ bool CallAndMessageChecker::uninitRefOrPointer(
if (PSV.isUndef()) {
if (ExplodedNode *N = C.generateErrorNode()) {
LazyInit_BT(BD, BT);
- auto R = llvm::make_unique<BugReport>(*BT, Os.str(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
R->addRange(ArgRange);
if (ArgEx)
bugreporter::trackExpressionValue(N, ArgEx, *R);
@@ -252,7 +252,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
SmallString<200> Buf;
llvm::raw_svector_ostream Os(Buf);
describeUninitializedArgumentInCall(Call, ArgumentNumber, Os);
- auto R = llvm::make_unique<BugReport>(*BT, Os.str(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
R->addRange(ArgRange);
if (ArgEx)
@@ -295,7 +295,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
}
// Generate a report for this bug.
- auto R = llvm::make_unique<BugReport>(*BT, os.str(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
R->addRange(ArgRange);
if (ArgEx)
@@ -358,7 +358,7 @@ void CallAndMessageChecker::checkPreStmt(const CXXDeleteExpr *DE,
else
Desc = "Argument to 'delete' is uninitialized";
BugType *BT = BT_cxx_delete_undef.get();
- auto R = llvm::make_unique<BugReport>(*BT, Desc, N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, Desc, N);
bugreporter::trackExpressionValue(N, DE, *R);
C.emitReport(std::move(R));
return;
@@ -420,8 +420,8 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
<< (Params == 1 ? "" : "s") << " is called with fewer ("
<< Call.getNumArgs() << ")";
- C.emitReport(
- llvm::make_unique<BugReport>(*BT_call_few_args, os.str(), N));
+ C.emitReport(std::make_unique<PathSensitiveBugReport>(*BT_call_few_args,
+ os.str(), N));
}
}
@@ -482,7 +482,7 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
}
assert(BT && "Unknown message kind.");
- auto R = llvm::make_unique<BugReport>(*BT, BT->getName(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
const ObjCMessageExpr *ME = msg.getOriginExpr();
R->addRange(ME->getReceiverRange());
@@ -525,7 +525,8 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
os << "' that will be garbage";
}
- auto report = llvm::make_unique<BugReport>(*BT_msg_ret, os.str(), N);
+ auto report =
+ std::make_unique<PathSensitiveBugReport>(*BT_msg_ret, os.str(), N);
report->addRange(ME->getReceiverRange());
// FIXME: This won't track "self" in messages to super.
if (const Expr *receiver = ME->getInstanceReceiver()) {
@@ -611,7 +612,7 @@ bool ento::shouldRegisterCallAndMessageChecker(const LangOptions &LO) {
void ento::registerCallAndMessageUnInitRefArg(CheckerManager &mgr) {
CallAndMessageChecker *Checker = mgr.getChecker<CallAndMessageChecker>();
Checker->Check_CallAndMessageUnInitRefArg = true;
- Checker->CheckName_CallAndMessageUnInitRefArg = mgr.getCurrentCheckName();
+ Checker->CheckName_CallAndMessageUnInitRefArg = mgr.getCurrentCheckerName();
}
bool ento::shouldRegisterCallAndMessageUnInitRefArg(const LangOptions &LO) {
diff --git a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index 05ece961467f..51c1d4409929 100644
--- a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
@@ -132,7 +132,8 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
BT.reset(new BuiltinBug(this, "Cast region with wrong size.",
"Cast a region whose size is not a multiple"
" of the destination type size."));
- auto R = llvm::make_unique<BugReport>(*BT, BT->getDescription(), errorNode);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(),
+ errorNode);
R->addRange(CE->getSourceRange());
C.emitReport(std::move(R));
}
diff --git a/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp b/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
index ff5d12c27c69..cc1c9a66b90e 100644
--- a/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
@@ -6,178 +6,429 @@
//
//===----------------------------------------------------------------------===//
//
-// This defines CastValueChecker which models casts of custom RTTIs.
+// This defines CastValueChecker which models casts of custom RTTIs.
+//
+// TODO list:
+// - It only allows one succesful cast between two types however in the wild
+// the object could be casted to multiple types.
+// - It needs to check the most likely type information from the dynamic type
+// map to increase precision of dynamic casting.
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/DeclTemplate.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
#include "llvm/ADT/Optional.h"
+#include <utility>
using namespace clang;
using namespace ento;
namespace {
class CastValueChecker : public Checker<eval::Call> {
+ enum class CallKind { Function, Method, InstanceOf };
+
using CastCheck =
- std::function<void(const CastValueChecker *, const CallExpr *,
+ std::function<void(const CastValueChecker *, const CallEvent &Call,
DefinedOrUnknownSVal, CheckerContext &)>;
public:
- // We have three cases to evaluate a cast:
- // 1) The parameter is non-null, the return value is non-null
- // 2) The parameter is non-null, the return value is null
- // 3) The parameter is null, the return value is null
- //
+ // We have five cases to evaluate a cast:
+ // 1) The parameter is non-null, the return value is non-null.
+ // 2) The parameter is non-null, the return value is null.
+ // 3) The parameter is null, the return value is null.
// cast: 1; dyn_cast: 1, 2; cast_or_null: 1, 3; dyn_cast_or_null: 1, 2, 3.
+ //
+ // 4) castAs: Has no parameter, the return value is non-null.
+ // 5) getAs: Has no parameter, the return value is null or non-null.
+ //
+ // We have two cases to check the parameter is an instance of the given type.
+ // 1) isa: The parameter is non-null, returns boolean.
+ // 2) isa_and_nonnull: The parameter is null or non-null, returns boolean.
bool evalCall(const CallEvent &Call, CheckerContext &C) const;
private:
- // These are known in the LLVM project.
- const CallDescriptionMap<CastCheck> CDM = {
- {{{"llvm", "cast"}, 1}, &CastValueChecker::evalCast},
- {{{"llvm", "dyn_cast"}, 1}, &CastValueChecker::evalDynCast},
- {{{"llvm", "cast_or_null"}, 1}, &CastValueChecker::evalCastOrNull},
+ // These are known in the LLVM project. The pairs are in the following form:
+ // {{{namespace, call}, argument-count}, {callback, kind}}
+ const CallDescriptionMap<std::pair<CastCheck, CallKind>> CDM = {
+ {{{"llvm", "cast"}, 1},
+ {&CastValueChecker::evalCast, CallKind::Function}},
+ {{{"llvm", "dyn_cast"}, 1},
+ {&CastValueChecker::evalDynCast, CallKind::Function}},
+ {{{"llvm", "cast_or_null"}, 1},
+ {&CastValueChecker::evalCastOrNull, CallKind::Function}},
{{{"llvm", "dyn_cast_or_null"}, 1},
- &CastValueChecker::evalDynCastOrNull}};
-
- void evalCast(const CallExpr *CE, DefinedOrUnknownSVal ParamDV,
+ {&CastValueChecker::evalDynCastOrNull, CallKind::Function}},
+ {{{"clang", "castAs"}, 0},
+ {&CastValueChecker::evalCastAs, CallKind::Method}},
+ {{{"clang", "getAs"}, 0},
+ {&CastValueChecker::evalGetAs, CallKind::Method}},
+ {{{"llvm", "isa"}, 1},
+ {&CastValueChecker::evalIsa, CallKind::InstanceOf}},
+ {{{"llvm", "isa_and_nonnull"}, 1},
+ {&CastValueChecker::evalIsaAndNonNull, CallKind::InstanceOf}}};
+
+ void evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
CheckerContext &C) const;
- void evalDynCast(const CallExpr *CE, DefinedOrUnknownSVal ParamDV,
+ void evalDynCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
CheckerContext &C) const;
- void evalCastOrNull(const CallExpr *CE, DefinedOrUnknownSVal ParamDV,
+ void evalCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
CheckerContext &C) const;
- void evalDynCastOrNull(const CallExpr *CE, DefinedOrUnknownSVal ParamDV,
+ void evalDynCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
+ CheckerContext &C) const;
+ void evalCastAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
+ CheckerContext &C) const;
+ void evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
+ CheckerContext &C) const;
+ void evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
+ CheckerContext &C) const;
+ void evalIsaAndNonNull(const CallEvent &Call, DefinedOrUnknownSVal DV,
CheckerContext &C) const;
};
} // namespace
-static std::string getCastName(const Expr *Cast) {
- return Cast->getType()->getPointeeCXXRecordDecl()->getNameAsString();
+static bool isInfeasibleCast(const DynamicCastInfo *CastInfo,
+ bool CastSucceeds) {
+ if (!CastInfo)
+ return false;
+
+ return CastSucceeds ? CastInfo->fails() : CastInfo->succeeds();
}
-static void evalNonNullParamNonNullReturn(const CallExpr *CE,
- DefinedOrUnknownSVal ParamDV,
- CheckerContext &C) {
- ProgramStateRef State = C.getState()->assume(ParamDV, true);
- if (!State)
- return;
+static const NoteTag *getNoteTag(CheckerContext &C,
+ const DynamicCastInfo *CastInfo,
+ QualType CastToTy, const Expr *Object,
+ bool CastSucceeds, bool IsKnownCast) {
+ std::string CastToName =
+ CastInfo ? CastInfo->to()->getPointeeCXXRecordDecl()->getNameAsString()
+ : CastToTy->getPointeeCXXRecordDecl()->getNameAsString();
+ Object = Object->IgnoreParenImpCasts();
+
+ return C.getNoteTag(
+ [=]() -> std::string {
+ SmallString<128> Msg;
+ llvm::raw_svector_ostream Out(Msg);
- State = State->BindExpr(CE, C.getLocationContext(), ParamDV, false);
+ if (!IsKnownCast)
+ Out << "Assuming ";
- std::string CastFromName = getCastName(CE->getArg(0));
- std::string CastToName = getCastName(CE);
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) {
+ Out << '\'' << DRE->getDecl()->getNameAsString() << '\'';
+ } else if (const auto *ME = dyn_cast<MemberExpr>(Object)) {
+ Out << (IsKnownCast ? "Field '" : "field '")
+ << ME->getMemberDecl()->getNameAsString() << '\'';
+ } else {
+ Out << (IsKnownCast ? "The object" : "the object");
+ }
- const NoteTag *CastTag = C.getNoteTag(
- [CastFromName, CastToName](BugReport &) -> std::string {
- SmallString<128> Msg;
- llvm::raw_svector_ostream Out(Msg);
+ Out << ' ' << (CastSucceeds ? "is a" : "is not a") << " '" << CastToName
+ << '\'';
- Out << "Assuming dynamic cast from '" << CastFromName << "' to '"
- << CastToName << "' succeeds";
return Out.str();
},
/*IsPrunable=*/true);
+}
- C.addTransition(State, CastTag);
+//===----------------------------------------------------------------------===//
+// Main logic to evaluate a cast.
+//===----------------------------------------------------------------------===//
+
+static QualType alignReferenceTypes(QualType toAlign, QualType alignTowards,
+ ASTContext &ACtx) {
+ if (alignTowards->isLValueReferenceType() &&
+ alignTowards.isConstQualified()) {
+ toAlign.addConst();
+ return ACtx.getLValueReferenceType(toAlign);
+ } else if (alignTowards->isLValueReferenceType())
+ return ACtx.getLValueReferenceType(toAlign);
+ else if (alignTowards->isRValueReferenceType())
+ return ACtx.getRValueReferenceType(toAlign);
+
+ llvm_unreachable("Must align towards a reference type!");
}
-static void evalNonNullParamNullReturn(const CallExpr *CE,
- DefinedOrUnknownSVal ParamDV,
- CheckerContext &C) {
- ProgramStateRef State = C.getState()->assume(ParamDV, true);
+static void addCastTransition(const CallEvent &Call, DefinedOrUnknownSVal DV,
+ CheckerContext &C, bool IsNonNullParam,
+ bool IsNonNullReturn,
+ bool IsCheckedCast = false) {
+ ProgramStateRef State = C.getState()->assume(DV, IsNonNullParam);
if (!State)
return;
- State = State->BindExpr(CE, C.getLocationContext(),
- C.getSValBuilder().makeNull(), false);
+ const Expr *Object;
+ QualType CastFromTy;
+ QualType CastToTy = Call.getResultType();
+
+ if (Call.getNumArgs() > 0) {
+ Object = Call.getArgExpr(0);
+ CastFromTy = Call.parameters()[0]->getType();
+ } else {
+ Object = cast<CXXInstanceCall>(&Call)->getCXXThisExpr();
+ CastFromTy = Object->getType();
+ if (CastToTy->isPointerType()) {
+ if (!CastFromTy->isPointerType())
+ return;
+ } else {
+ if (!CastFromTy->isReferenceType())
+ return;
+
+ CastFromTy = alignReferenceTypes(CastFromTy, CastToTy, C.getASTContext());
+ }
+ }
+
+ const MemRegion *MR = DV.getAsRegion();
+ const DynamicCastInfo *CastInfo =
+ getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
+
+ // We assume that every checked cast succeeds.
+ bool CastSucceeds = IsCheckedCast || CastFromTy == CastToTy;
+ if (!CastSucceeds) {
+ if (CastInfo)
+ CastSucceeds = IsNonNullReturn && CastInfo->succeeds();
+ else
+ CastSucceeds = IsNonNullReturn;
+ }
+
+ // Check for infeasible casts.
+ if (isInfeasibleCast(CastInfo, CastSucceeds)) {
+ C.generateSink(State, C.getPredecessor());
+ return;
+ }
+
+ // Store the type and the cast information.
+ bool IsKnownCast = CastInfo || IsCheckedCast || CastFromTy == CastToTy;
+ if (!IsKnownCast || IsCheckedCast)
+ State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
+ CastSucceeds);
+
+ SVal V = CastSucceeds ? C.getSValBuilder().evalCast(DV, CastToTy, CastFromTy)
+ : C.getSValBuilder().makeNull();
+ C.addTransition(
+ State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), V, false),
+ getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast));
+}
- std::string CastFromName = getCastName(CE->getArg(0));
- std::string CastToName = getCastName(CE);
+static void addInstanceOfTransition(const CallEvent &Call,
+ DefinedOrUnknownSVal DV,
+ ProgramStateRef State, CheckerContext &C,
+ bool IsInstanceOf) {
+ const FunctionDecl *FD = Call.getDecl()->getAsFunction();
+ QualType CastFromTy = Call.parameters()[0]->getType();
+ QualType CastToTy = FD->getTemplateSpecializationArgs()->get(0).getAsType();
+ if (CastFromTy->isPointerType())
+ CastToTy = C.getASTContext().getPointerType(CastToTy);
+ else if (CastFromTy->isReferenceType())
+ CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext());
+ else
+ return;
- const NoteTag *CastTag = C.getNoteTag(
- [CastFromName, CastToName](BugReport &) -> std::string {
- SmallString<128> Msg;
- llvm::raw_svector_ostream Out(Msg);
+ const MemRegion *MR = DV.getAsRegion();
+ const DynamicCastInfo *CastInfo =
+ getDynamicCastInfo(State, MR, CastFromTy, CastToTy);
- Out << "Assuming dynamic cast from '" << CastFromName << "' to '"
- << CastToName << "' fails";
- return Out.str();
- },
- /*IsPrunable=*/true);
+ bool CastSucceeds;
+ if (CastInfo)
+ CastSucceeds = IsInstanceOf && CastInfo->succeeds();
+ else
+ CastSucceeds = IsInstanceOf || CastFromTy == CastToTy;
- C.addTransition(State, CastTag);
+ if (isInfeasibleCast(CastInfo, CastSucceeds)) {
+ C.generateSink(State, C.getPredecessor());
+ return;
+ }
+
+ // Store the type and the cast information.
+ bool IsKnownCast = CastInfo || CastFromTy == CastToTy;
+ if (!IsKnownCast)
+ State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy,
+ IsInstanceOf);
+
+ C.addTransition(
+ State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
+ C.getSValBuilder().makeTruthVal(CastSucceeds)),
+ getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), CastSucceeds,
+ IsKnownCast));
}
-static void evalNullParamNullReturn(const CallExpr *CE,
- DefinedOrUnknownSVal ParamDV,
- CheckerContext &C) {
- ProgramStateRef State = C.getState()->assume(ParamDV, false);
- if (!State)
- return;
+//===----------------------------------------------------------------------===//
+// Evaluating cast, dyn_cast, cast_or_null, dyn_cast_or_null.
+//===----------------------------------------------------------------------===//
- State = State->BindExpr(CE, C.getLocationContext(),
- C.getSValBuilder().makeNull(), false);
+static void evalNonNullParamNonNullReturn(const CallEvent &Call,
+ DefinedOrUnknownSVal DV,
+ CheckerContext &C,
+ bool IsCheckedCast = false) {
+ addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
+ /*IsNonNullReturn=*/true, IsCheckedCast);
+}
- const NoteTag *CastTag =
- C.getNoteTag("Assuming null pointer is passed into cast",
- /*IsPrunable=*/true);
+static void evalNonNullParamNullReturn(const CallEvent &Call,
+ DefinedOrUnknownSVal DV,
+ CheckerContext &C) {
+ addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
+ /*IsNonNullReturn=*/false);
+}
- C.addTransition(State, CastTag);
+static void evalNullParamNullReturn(const CallEvent &Call,
+ DefinedOrUnknownSVal DV,
+ CheckerContext &C) {
+ if (ProgramStateRef State = C.getState()->assume(DV, false))
+ C.addTransition(State->BindExpr(Call.getOriginExpr(),
+ C.getLocationContext(),
+ C.getSValBuilder().makeNull(), false),
+ C.getNoteTag("Assuming null pointer is passed into cast",
+ /*IsPrunable=*/true));
}
-void CastValueChecker::evalCast(const CallExpr *CE,
- DefinedOrUnknownSVal ParamDV,
+void CastValueChecker::evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV,
CheckerContext &C) const {
- evalNonNullParamNonNullReturn(CE, ParamDV, C);
+ evalNonNullParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
}
-void CastValueChecker::evalDynCast(const CallExpr *CE,
- DefinedOrUnknownSVal ParamDV,
+void CastValueChecker::evalDynCast(const CallEvent &Call,
+ DefinedOrUnknownSVal DV,
CheckerContext &C) const {
- evalNonNullParamNonNullReturn(CE, ParamDV, C);
- evalNonNullParamNullReturn(CE, ParamDV, C);
+ evalNonNullParamNonNullReturn(Call, DV, C);
+ evalNonNullParamNullReturn(Call, DV, C);
}
-void CastValueChecker::evalCastOrNull(const CallExpr *CE,
- DefinedOrUnknownSVal ParamDV,
+void CastValueChecker::evalCastOrNull(const CallEvent &Call,
+ DefinedOrUnknownSVal DV,
CheckerContext &C) const {
- evalNonNullParamNonNullReturn(CE, ParamDV, C);
- evalNullParamNullReturn(CE, ParamDV, C);
+ evalNonNullParamNonNullReturn(Call, DV, C);
+ evalNullParamNullReturn(Call, DV, C);
}
-void CastValueChecker::evalDynCastOrNull(const CallExpr *CE,
- DefinedOrUnknownSVal ParamDV,
+void CastValueChecker::evalDynCastOrNull(const CallEvent &Call,
+ DefinedOrUnknownSVal DV,
CheckerContext &C) const {
- evalNonNullParamNonNullReturn(CE, ParamDV, C);
- evalNonNullParamNullReturn(CE, ParamDV, C);
- evalNullParamNullReturn(CE, ParamDV, C);
+ evalNonNullParamNonNullReturn(Call, DV, C);
+ evalNonNullParamNullReturn(Call, DV, C);
+ evalNullParamNullReturn(Call, DV, C);
}
-bool CastValueChecker::evalCall(const CallEvent &Call,
- CheckerContext &C) const {
- const CastCheck *Check = CDM.lookup(Call);
- if (!Check)
- return false;
+//===----------------------------------------------------------------------===//
+// Evaluating castAs, getAs.
+//===----------------------------------------------------------------------===//
- const auto *CE = cast<CallExpr>(Call.getOriginExpr());
- if (!CE)
- return false;
+static void evalZeroParamNonNullReturn(const CallEvent &Call,
+ DefinedOrUnknownSVal DV,
+ CheckerContext &C,
+ bool IsCheckedCast = false) {
+ addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
+ /*IsNonNullReturn=*/true, IsCheckedCast);
+}
+
+static void evalZeroParamNullReturn(const CallEvent &Call,
+ DefinedOrUnknownSVal DV,
+ CheckerContext &C) {
+ addCastTransition(Call, DV, C, /*IsNonNullParam=*/true,
+ /*IsNonNullReturn=*/false);
+}
+
+void CastValueChecker::evalCastAs(const CallEvent &Call,
+ DefinedOrUnknownSVal DV,
+ CheckerContext &C) const {
+ evalZeroParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true);
+}
+
+void CastValueChecker::evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV,
+ CheckerContext &C) const {
+ evalZeroParamNonNullReturn(Call, DV, C);
+ evalZeroParamNullReturn(Call, DV, C);
+}
- // If we cannot obtain both of the classes we cannot be sure how to model it.
- if (!CE->getType()->getPointeeCXXRecordDecl() ||
- !CE->getArg(0)->getType()->getPointeeCXXRecordDecl())
+//===----------------------------------------------------------------------===//
+// Evaluating isa, isa_and_nonnull.
+//===----------------------------------------------------------------------===//
+
+void CastValueChecker::evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV,
+ CheckerContext &C) const {
+ ProgramStateRef NonNullState, NullState;
+ std::tie(NonNullState, NullState) = C.getState()->assume(DV);
+
+ if (NonNullState) {
+ addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
+ addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
+ }
+
+ if (NullState) {
+ C.generateSink(NullState, C.getPredecessor());
+ }
+}
+
+void CastValueChecker::evalIsaAndNonNull(const CallEvent &Call,
+ DefinedOrUnknownSVal DV,
+ CheckerContext &C) const {
+ ProgramStateRef NonNullState, NullState;
+ std::tie(NonNullState, NullState) = C.getState()->assume(DV);
+
+ if (NonNullState) {
+ addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true);
+ addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false);
+ }
+
+ if (NullState) {
+ addInstanceOfTransition(Call, DV, NullState, C, /*IsInstanceOf=*/false);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Main logic to evaluate a call.
+//===----------------------------------------------------------------------===//
+
+bool CastValueChecker::evalCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ const auto *Lookup = CDM.lookup(Call);
+ if (!Lookup)
return false;
- SVal ParamV = Call.getArgSVal(0);
- auto ParamDV = ParamV.getAs<DefinedOrUnknownSVal>();
- if (!ParamDV)
+ const CastCheck &Check = Lookup->first;
+ CallKind Kind = Lookup->second;
+
+ Optional<DefinedOrUnknownSVal> DV;
+
+ switch (Kind) {
+ case CallKind::Function: {
+ // We only model casts from pointers to pointers or from references
+ // to references. Other casts are most likely specialized and we
+ // cannot model them.
+ QualType ParamT = Call.parameters()[0]->getType();
+ QualType ResultT = Call.getResultType();
+ if (!(ParamT->isPointerType() && ResultT->isPointerType()) &&
+ !(ParamT->isReferenceType() && ResultT->isReferenceType()))
+ return false;
+
+ DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
+ break;
+ }
+ case CallKind::InstanceOf: {
+ // We need to obtain the only template argument to determinte the type.
+ const FunctionDecl *FD = Call.getDecl()->getAsFunction();
+ if (!FD || !FD->getTemplateSpecializationArgs())
+ return false;
+
+ DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
+ break;
+ }
+ case CallKind::Method:
+ const auto *InstanceCall = dyn_cast<CXXInstanceCall>(&Call);
+ if (!InstanceCall)
+ return false;
+
+ DV = InstanceCall->getCXXThisVal().getAs<DefinedOrUnknownSVal>();
+ break;
+ }
+
+ if (!DV)
return false;
- (*Check)(this, CE, *ParamDV, C);
+ Check(this, Call, *DV, C);
return true;
}
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index a7ca814c8f96..50b872bd8682 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -28,6 +28,7 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
@@ -36,7 +37,6 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
@@ -576,9 +576,8 @@ void ObjCDeallocChecker::diagnoseMissingReleases(CheckerContext &C) const {
OS << " by a synthesized property but not released"
" before '[super dealloc]'";
- std::unique_ptr<BugReport> BR(
- new BugReport(*MissingReleaseBugType, OS.str(), ErrNode));
-
+ auto BR = std::make_unique<PathSensitiveBugReport>(*MissingReleaseBugType,
+ OS.str(), ErrNode);
C.emitReport(std::move(BR));
}
@@ -699,8 +698,8 @@ bool ObjCDeallocChecker::diagnoseExtraRelease(SymbolRef ReleasedValue,
OS << " property but was released in 'dealloc'";
}
- std::unique_ptr<BugReport> BR(
- new BugReport(*ExtraReleaseBugType, OS.str(), ErrNode));
+ auto BR = std::make_unique<PathSensitiveBugReport>(*ExtraReleaseBugType,
+ OS.str(), ErrNode);
BR->addRange(M.getOriginExpr()->getSourceRange());
C.emitReport(std::move(BR));
@@ -741,8 +740,8 @@ bool ObjCDeallocChecker::diagnoseMistakenDealloc(SymbolRef DeallocedValue,
OS << "'" << *PropImpl->getPropertyIvarDecl()
<< "' should be released rather than deallocated";
- std::unique_ptr<BugReport> BR(
- new BugReport(*MistakenDeallocBugType, OS.str(), ErrNode));
+ auto BR = std::make_unique<PathSensitiveBugReport>(*MistakenDeallocBugType,
+ OS.str(), ErrNode);
BR->addRange(M.getOriginExpr()->getSourceRange());
C.emitReport(std::move(BR));
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
index a020d33bfd95..1694c237cda4 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
@@ -13,11 +13,11 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Type.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index 3f1c213a5647..260a2896e78c 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -50,19 +50,19 @@ struct ChecksFilter {
DefaultBool check_FloatLoopCounter;
DefaultBool check_UncheckedReturn;
- CheckName checkName_bcmp;
- CheckName checkName_bcopy;
- CheckName checkName_bzero;
- CheckName checkName_gets;
- CheckName checkName_getpw;
- CheckName checkName_mktemp;
- CheckName checkName_mkstemp;
- CheckName checkName_strcpy;
- CheckName checkName_DeprecatedOrUnsafeBufferHandling;
- CheckName checkName_rand;
- CheckName checkName_vfork;
- CheckName checkName_FloatLoopCounter;
- CheckName checkName_UncheckedReturn;
+ CheckerNameRef checkName_bcmp;
+ CheckerNameRef checkName_bcopy;
+ CheckerNameRef checkName_bzero;
+ CheckerNameRef checkName_gets;
+ CheckerNameRef checkName_getpw;
+ CheckerNameRef checkName_mktemp;
+ CheckerNameRef checkName_mkstemp;
+ CheckerNameRef checkName_strcpy;
+ CheckerNameRef checkName_DeprecatedOrUnsafeBufferHandling;
+ CheckerNameRef checkName_rand;
+ CheckerNameRef checkName_vfork;
+ CheckerNameRef checkName_FloatLoopCounter;
+ CheckerNameRef checkName_UncheckedReturn;
};
class WalkAST : public StmtVisitor<WalkAST> {
@@ -204,6 +204,8 @@ void WalkAST::VisitForStmt(ForStmt *FS) {
// Implements: CERT security coding advisory FLP-30.
//===----------------------------------------------------------------------===//
+// Returns either 'x' or 'y', depending on which one of them is incremented
+// in 'expr', or nullptr if none of them is incremented.
static const DeclRefExpr*
getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
expr = expr->IgnoreParenCasts();
@@ -289,14 +291,15 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
// Does either variable appear in increment?
const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
-
if (!drInc)
return;
+ const VarDecl *vdInc = cast<VarDecl>(drInc->getDecl());
+ assert(vdInc && (vdInc == vdLHS || vdInc == vdRHS));
+
// Emit the error. First figure out which DeclRefExpr in the condition
// referenced the compared variable.
- assert(drInc->getDecl());
- const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
+ const DeclRefExpr *drCond = vdLHS == vdInc ? drLHS : drRHS;
SmallVector<SourceRange, 2> ranges;
SmallString<256> sbuf;
@@ -1012,14 +1015,12 @@ bool ento::shouldRegisterSecuritySyntaxChecker(const LangOptions &LO) {
#define REGISTER_CHECKER(name) \
void ento::register##name(CheckerManager &mgr) { \
- SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>(); \
+ SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>(); \
checker->filter.check_##name = true; \
- checker->filter.checkName_##name = mgr.getCurrentCheckName(); \
+ checker->filter.checkName_##name = mgr.getCurrentCheckerName(); \
} \
\
- bool ento::shouldRegister##name(const LangOptions &LO) { \
- return true; \
- }
+ bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
REGISTER_CHECKER(bcmp)
REGISTER_CHECKER(bcopy)
diff --git a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index 9fffedfccd87..7a41a7b6b216 100644
--- a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -127,7 +127,7 @@ void ChrootChecker::checkPreCall(const CallEvent &Call,
BT_BreakJail.reset(new BuiltinBug(
this, "Break out of jail", "No call of chdir(\"/\") immediately "
"after chroot"));
- C.emitReport(llvm::make_unique<BugReport>(
+ C.emitReport(std::make_unique<PathSensitiveBugReport>(
*BT_BreakJail, BT_BreakJail->getDescription(), N));
}
}
diff --git a/lib/StaticAnalyzer/Checkers/CloneChecker.cpp b/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
index 4fc225056d4c..ce45b5be34c9 100644
--- a/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CloneChecker.cpp
@@ -114,8 +114,8 @@ void CloneChecker::reportClones(
for (const CloneDetector::CloneGroup &Group : CloneGroups) {
// We group the clones by printing the first as a warning and all others
// as a note.
- auto R = llvm::make_unique<BugReport>(*BT_Exact, "Duplicate code detected",
- makeLocation(Group.front(), Mgr));
+ auto R = std::make_unique<BasicBugReport>(
+ *BT_Exact, "Duplicate code detected", makeLocation(Group.front(), Mgr));
R->addRange(Group.front().getSourceRange());
for (unsigned i = 1; i < Group.size(); ++i)
@@ -169,7 +169,7 @@ void CloneChecker::reportSuspiciousClones(
// which may confuse the user.
// Think how to perform more accurate suggestions?
- auto R = llvm::make_unique<BugReport>(
+ auto R = std::make_unique<BasicBugReport>(
*BT_Suspicious,
"Potential copy-paste error; did you really mean to use '" +
Pair.FirstCloneInfo.Variable->getNameAsString() + "' here?",
diff --git a/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp b/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
index 5058d101b8e5..8dd3132f07e2 100644
--- a/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
@@ -121,7 +121,7 @@ void ConversionChecker::reportBug(ExplodedNode *N, CheckerContext &C,
new BuiltinBug(this, "Conversion", "Possible loss of sign/precision."));
// Generate a report for this bug.
- auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
C.emitReport(std::move(R));
}
diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index d5baa2bcba6f..61441889fc64 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Lex/Lexer.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
@@ -119,11 +120,20 @@ LookThroughTransitiveAssignmentsAndCommaOperators(const Expr *Ex) {
}
namespace {
+class DeadStoresChecker : public Checker<check::ASTCodeBody> {
+public:
+ bool ShowFixIts = false;
+ bool WarnForDeadNestedAssignments = true;
+
+ void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
+ BugReporter &BR) const;
+};
+
class DeadStoreObs : public LiveVariables::Observer {
const CFG &cfg;
ASTContext &Ctx;
BugReporter& BR;
- const CheckerBase *Checker;
+ const DeadStoresChecker *Checker;
AnalysisDeclContext* AC;
ParentMap& Parents;
llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
@@ -135,9 +145,10 @@ class DeadStoreObs : public LiveVariables::Observer {
public:
DeadStoreObs(const CFG &cfg, ASTContext &ctx, BugReporter &br,
- const CheckerBase *checker, AnalysisDeclContext *ac,
+ const DeadStoresChecker *checker, AnalysisDeclContext *ac,
ParentMap &parents,
- llvm::SmallPtrSet<const VarDecl *, 20> &escaped)
+ llvm::SmallPtrSet<const VarDecl *, 20> &escaped,
+ bool warnForDeadNestedAssignments)
: cfg(cfg), Ctx(ctx), BR(br), Checker(checker), AC(ac), Parents(parents),
Escaped(escaped), currentBlock(nullptr) {}
@@ -202,12 +213,32 @@ public:
llvm::raw_svector_ostream os(buf);
const char *BugType = nullptr;
+ SmallVector<FixItHint, 1> Fixits;
+
switch (dsk) {
- case DeadInit:
+ case DeadInit: {
BugType = "Dead initialization";
os << "Value stored to '" << *V
<< "' during its initialization is never read";
+
+ ASTContext &ACtx = V->getASTContext();
+ if (Checker->ShowFixIts) {
+ if (V->getInit()->HasSideEffects(ACtx,
+ /*IncludePossibleEffects=*/true)) {
+ break;
+ }
+ SourceManager &SM = ACtx.getSourceManager();
+ const LangOptions &LO = ACtx.getLangOpts();
+ SourceLocation L1 =
+ Lexer::findNextToken(
+ V->getTypeSourceInfo()->getTypeLoc().getEndLoc(),
+ SM, LO)->getEndLoc();
+ SourceLocation L2 =
+ Lexer::getLocForEndOfToken(V->getInit()->getEndLoc(), 1, SM, LO);
+ Fixits.push_back(FixItHint::CreateRemoval({L1, L2}));
+ }
break;
+ }
case DeadIncrement:
BugType = "Dead increment";
@@ -217,15 +248,20 @@ public:
os << "Value stored to '" << *V << "' is never read";
break;
+ // eg.: f((x = foo()))
case Enclosing:
- // Don't report issues in this case, e.g.: "if (x = foo())",
- // where 'x' is unused later. We have yet to see a case where
- // this is a real bug.
- return;
+ if (!Checker->WarnForDeadNestedAssignments)
+ return;
+ BugType = "Dead nested assignment";
+ os << "Although the value stored to '" << *V
+ << "' is used in the enclosing expression, the value is never "
+ "actually read from '"
+ << *V << "'";
+ break;
}
BR.EmitBasicReport(AC->getDecl(), Checker, BugType, "Dead store", os.str(),
- L, R);
+ L, R, Fixits);
}
void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val,
@@ -471,35 +507,37 @@ public:
// DeadStoresChecker
//===----------------------------------------------------------------------===//
-namespace {
-class DeadStoresChecker : public Checker<check::ASTCodeBody> {
-public:
- void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
- BugReporter &BR) const {
-
- // Don't do anything for template instantiations.
- // Proving that code in a template instantiation is "dead"
- // means proving that it is dead in all instantiations.
- // This same problem exists with -Wunreachable-code.
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- if (FD->isTemplateInstantiation())
- return;
+void DeadStoresChecker::checkASTCodeBody(const Decl *D, AnalysisManager &mgr,
+ BugReporter &BR) const {
- if (LiveVariables *L = mgr.getAnalysis<LiveVariables>(D)) {
- CFG &cfg = *mgr.getCFG(D);
- AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D);
- ParentMap &pmap = mgr.getParentMap(D);
- FindEscaped FS;
- cfg.VisitBlockStmts(FS);
- DeadStoreObs A(cfg, BR.getContext(), BR, this, AC, pmap, FS.Escaped);
- L->runOnAllBlocks(A);
- }
+ // Don't do anything for template instantiations.
+ // Proving that code in a template instantiation is "dead"
+ // means proving that it is dead in all instantiations.
+ // This same problem exists with -Wunreachable-code.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->isTemplateInstantiation())
+ return;
+
+ if (LiveVariables *L = mgr.getAnalysis<LiveVariables>(D)) {
+ CFG &cfg = *mgr.getCFG(D);
+ AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D);
+ ParentMap &pmap = mgr.getParentMap(D);
+ FindEscaped FS;
+ cfg.VisitBlockStmts(FS);
+ DeadStoreObs A(cfg, BR.getContext(), BR, this, AC, pmap, FS.Escaped,
+ WarnForDeadNestedAssignments);
+ L->runOnAllBlocks(A);
}
-};
}
-void ento::registerDeadStoresChecker(CheckerManager &mgr) {
- mgr.registerChecker<DeadStoresChecker>();
+void ento::registerDeadStoresChecker(CheckerManager &Mgr) {
+ auto *Chk = Mgr.registerChecker<DeadStoresChecker>();
+
+ const AnalyzerOptions &AnOpts = Mgr.getAnalyzerOptions();
+ Chk->WarnForDeadNestedAssignments =
+ AnOpts.getCheckerBooleanOption(Chk, "WarnForDeadNestedAssignments");
+ Chk->ShowFixIts =
+ AnOpts.getCheckerBooleanOption(Chk, "ShowFixIts");
}
bool ento::shouldRegisterDeadStoresChecker(const LangOptions &LO) {
diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index bb9e8110b647..0cb4be2c7fdc 100644
--- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -333,7 +333,8 @@ public:
if (!Node)
return;
- auto Report = llvm::make_unique<BugReport>(BT_stmtLoc, "Statement", Node);
+ auto Report =
+ std::make_unique<PathSensitiveBugReport>(BT_stmtLoc, "Statement", Node);
C.emitReport(std::move(Report));
}
diff --git a/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp b/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp
index 8bf77c109f8a..45c1984c5e15 100644
--- a/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp
@@ -27,7 +27,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
using namespace clang;
@@ -45,9 +45,9 @@ class DeleteWithNonVirtualDtorChecker
static int X = 0;
ID.AddPointer(&X);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
private:
bool Satisfied;
@@ -92,23 +92,23 @@ void DeleteWithNonVirtualDtorChecker::checkPreStmt(const CXXDeleteExpr *DE,
"Logic error"));
ExplodedNode *N = C.generateNonFatalErrorNode();
- auto R = llvm::make_unique<BugReport>(*BT, BT->getName(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
// Mark region of problematic base class for later use in the BugVisitor.
R->markInteresting(BaseClassRegion);
- R->addVisitor(llvm::make_unique<DeleteBugVisitor>());
+ R->addVisitor(std::make_unique<DeleteBugVisitor>());
C.emitReport(std::move(R));
}
-std::shared_ptr<PathDiagnosticPiece>
+PathDiagnosticPieceRef
DeleteWithNonVirtualDtorChecker::DeleteBugVisitor::VisitNode(
const ExplodedNode *N, BugReporterContext &BRC,
- BugReport &BR) {
+ PathSensitiveBugReport &BR) {
// Stop traversal after the first conversion was found on a path.
if (Satisfied)
return nullptr;
- const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ const Stmt *S = N->getStmtForDiagnostics();
if (!S)
return nullptr;
@@ -140,8 +140,7 @@ DeleteWithNonVirtualDtorChecker::DeleteBugVisitor::VisitNode(
OS << "Conversion from derived to base happened here";
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
N->getLocationContext());
- return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true,
- nullptr);
+ return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true);
}
void ento::registerDeleteWithNonVirtualDtorChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index 2c264833f2a9..e3de0b4f4a7f 100644
--- a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -179,7 +179,7 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
break;
}
- auto report = llvm::make_unique<BugReport>(
+ auto report = std::make_unique<PathSensitiveBugReport>(
*BT_null, buf.empty() ? BT_null->getDescription() : StringRef(buf), N);
bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report);
@@ -200,8 +200,8 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
BT_undef.reset(
new BuiltinBug(this, "Dereference of undefined pointer value"));
- auto report =
- llvm::make_unique<BugReport>(*BT_undef, BT_undef->getDescription(), N);
+ auto report = std::make_unique<PathSensitiveBugReport>(
+ *BT_undef, BT_undef->getDescription(), N);
bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report);
C.emitReport(std::move(report));
}
diff --git a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
index 33e8fcd8af7b..8798bde88dcd 100644
--- a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
@@ -47,7 +47,7 @@ void DivZeroChecker::reportBug(
if (!BT)
BT.reset(new BuiltinBug(this, "Division by zero"));
- auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
R->addVisitor(std::move(Visitor));
bugreporter::trackExpressionValue(N, getDenomExpr(N), *R);
C.emitReport(std::move(R));
@@ -88,7 +88,7 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
bool TaintedD = isTainted(C.getState(), *DV);
if ((stateNotZero && stateZero && TaintedD)) {
reportBug("Division by a tainted value, possibly zero", stateZero, C,
- llvm::make_unique<taint::TaintBugVisitor>(*DV));
+ std::make_unique<taint::TaintBugVisitor>(*DV));
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp
index 4d979dc9f240..8cc38f9735f3 100644
--- a/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp
@@ -21,7 +21,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
@@ -47,9 +47,9 @@ class DynamicTypeChecker : public Checker<check::PostStmt<ImplicitCastExpr>> {
ID.AddPointer(Reg);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
private:
// The tracked region.
@@ -80,18 +80,16 @@ void DynamicTypeChecker::reportTypeError(QualType DynamicType,
QualType::print(StaticType.getTypePtr(), Qualifiers(), OS, C.getLangOpts(),
llvm::Twine());
OS << "'";
- std::unique_ptr<BugReport> R(
- new BugReport(*BT, OS.str(), C.generateNonFatalErrorNode()));
+ auto R = std::make_unique<PathSensitiveBugReport>(
+ *BT, OS.str(), C.generateNonFatalErrorNode());
R->markInteresting(Reg);
- R->addVisitor(llvm::make_unique<DynamicTypeBugVisitor>(Reg));
+ R->addVisitor(std::make_unique<DynamicTypeBugVisitor>(Reg));
R->addRange(ReportedNode->getSourceRange());
C.emitReport(std::move(R));
}
-std::shared_ptr<PathDiagnosticPiece>
-DynamicTypeChecker::DynamicTypeBugVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &) {
+PathDiagnosticPieceRef DynamicTypeChecker::DynamicTypeBugVisitor::VisitNode(
+ const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &) {
ProgramStateRef State = N->getState();
ProgramStateRef StatePrev = N->getFirstPred()->getState();
@@ -105,7 +103,7 @@ DynamicTypeChecker::DynamicTypeBugVisitor::VisitNode(const ExplodedNode *N,
return nullptr;
// Retrieve the associated statement.
- const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ const Stmt *S = N->getStmtForDiagnostics();
if (!S)
return nullptr;
@@ -141,8 +139,7 @@ DynamicTypeChecker::DynamicTypeBugVisitor::VisitNode(const ExplodedNode *N,
// Generate the extra diagnostic.
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
N->getLocationContext());
- return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true,
- nullptr);
+ return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true);
}
static bool hasDefinition(const ObjCObjectPointerType *ObjPtr) {
diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index 3cfe4dc82a10..cce3449b8873 100644
--- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -20,16 +20,16 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Builtins.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
using namespace clang;
@@ -83,9 +83,9 @@ class DynamicTypePropagation:
ID.AddPointer(Sym);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
private:
// The tracked symbol.
@@ -113,14 +113,7 @@ public:
void DynamicTypePropagation::checkDeadSymbols(SymbolReaper &SR,
CheckerContext &C) const {
- ProgramStateRef State = C.getState();
- DynamicTypeMapTy TypeMap = State->get<DynamicTypeMap>();
- for (DynamicTypeMapTy::iterator I = TypeMap.begin(), E = TypeMap.end();
- I != E; ++I) {
- if (!SR.isLiveRegion(I->first)) {
- State = State->remove<DynamicTypeMap>(I->first);
- }
- }
+ ProgramStateRef State = removeDeadTypes(C.getState(), SR);
MostSpecializedTypeArgsMapTy TyArgMap =
State->get<MostSpecializedTypeArgsMap>();
@@ -401,11 +394,11 @@ static const ObjCObjectPointerType *getMostInformativeDerivedClassImpl(
}
const auto *SuperOfTo =
- To->getObjectType()->getSuperClassType()->getAs<ObjCObjectType>();
+ To->getObjectType()->getSuperClassType()->castAs<ObjCObjectType>();
assert(SuperOfTo);
QualType SuperPtrOfToQual =
C.getObjCObjectPointerType(QualType(SuperOfTo, 0));
- const auto *SuperPtrOfTo = SuperPtrOfToQual->getAs<ObjCObjectPointerType>();
+ const auto *SuperPtrOfTo = SuperPtrOfToQual->castAs<ObjCObjectPointerType>();
if (To->isUnspecialized())
return getMostInformativeDerivedClassImpl(From, SuperPtrOfTo, SuperPtrOfTo,
C);
@@ -834,16 +827,15 @@ void DynamicTypePropagation::checkPostObjCMessage(const ObjCMethodCall &M,
if (MessageExpr->getReceiverKind() == ObjCMessageExpr::Class &&
Sel.getAsString() == "class") {
QualType ReceiverType = MessageExpr->getClassReceiver();
- const auto *ReceiverClassType = ReceiverType->getAs<ObjCObjectType>();
+ const auto *ReceiverClassType = ReceiverType->castAs<ObjCObjectType>();
+ if (!ReceiverClassType->isSpecialized())
+ return;
+
QualType ReceiverClassPointerType =
C.getASTContext().getObjCObjectPointerType(
QualType(ReceiverClassType, 0));
-
- if (!ReceiverClassType->isSpecialized())
- return;
const auto *InferredType =
- ReceiverClassPointerType->getAs<ObjCObjectPointerType>();
- assert(InferredType);
+ ReceiverClassPointerType->castAs<ObjCObjectPointerType>();
State = State->set<MostSpecializedTypeArgsMap>(RetSym, InferredType);
C.addTransition(State);
@@ -882,7 +874,7 @@ void DynamicTypePropagation::checkPostObjCMessage(const ObjCMethodCall &M,
// When there is an entry available for the return symbol in DynamicTypeMap,
// the call was inlined, and the information in the DynamicTypeMap is should
// be precise.
- if (RetRegion && !State->get<DynamicTypeMap>(RetRegion)) {
+ if (RetRegion && !getRawDynamicTypeInfo(State, RetRegion)) {
// TODO: we have duplicated information in DynamicTypeMap and
// MostSpecializedTypeArgsMap. We should only store anything in the later if
// the stored data differs from the one stored in the former.
@@ -919,19 +911,18 @@ void DynamicTypePropagation::reportGenericsBug(
OS << "' to incompatible type '";
QualType::print(To, Qualifiers(), OS, C.getLangOpts(), llvm::Twine());
OS << "'";
- std::unique_ptr<BugReport> R(
- new BugReport(*ObjCGenericsBugType, OS.str(), N));
+ auto R = std::make_unique<PathSensitiveBugReport>(*ObjCGenericsBugType,
+ OS.str(), N);
R->markInteresting(Sym);
- R->addVisitor(llvm::make_unique<GenericsBugVisitor>(Sym));
+ R->addVisitor(std::make_unique<GenericsBugVisitor>(Sym));
if (ReportedNode)
R->addRange(ReportedNode->getSourceRange());
C.emitReport(std::move(R));
}
-std::shared_ptr<PathDiagnosticPiece>
-DynamicTypePropagation::GenericsBugVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) {
+PathDiagnosticPieceRef DynamicTypePropagation::GenericsBugVisitor::VisitNode(
+ const ExplodedNode *N, BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
ProgramStateRef state = N->getState();
ProgramStateRef statePrev = N->getFirstPred()->getState();
@@ -946,7 +937,7 @@ DynamicTypePropagation::GenericsBugVisitor::VisitNode(const ExplodedNode *N,
return nullptr;
// Retrieve the associated statement.
- const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ const Stmt *S = N->getStmtForDiagnostics();
if (!S)
return nullptr;
@@ -981,8 +972,7 @@ DynamicTypePropagation::GenericsBugVisitor::VisitNode(const ExplodedNode *N,
// Generate the extra diagnostic.
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
N->getLocationContext());
- return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true,
- nullptr);
+ return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true);
}
/// Register checkers.
diff --git a/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp b/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
index 736d80ef9ec7..481a5685a71f 100644
--- a/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
@@ -83,7 +83,7 @@ void EnumCastOutOfRangeChecker::reportWarning(CheckerContext &C) const {
new BuiltinBug(this, "Enum cast out of range",
"The value provided to the cast expression is not in "
"the valid range of values for the enum"));
- C.emitReport(llvm::make_unique<BugReport>(
+ C.emitReport(std::make_unique<PathSensitiveBugReport>(
*EnumValueCastOutOfRange, EnumValueCastOutOfRange->getDescription(),
N));
}
@@ -91,6 +91,22 @@ void EnumCastOutOfRangeChecker::reportWarning(CheckerContext &C) const {
void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE,
CheckerContext &C) const {
+
+ // Only perform enum range check on casts where such checks are valid. For
+ // all other cast kinds (where enum range checks are unnecessary or invalid),
+ // just return immediately. TODO: The set of casts whitelisted for enum
+ // range checking may be incomplete. Better to add a missing cast kind to
+ // enable a missing check than to generate false negatives and have to remove
+ // those later.
+ switch (CE->getCastKind()) {
+ case CK_IntegralCast:
+ break;
+
+ default:
+ return;
+ break;
+ }
+
// Get the value of the expression to cast.
const llvm::Optional<DefinedOrUnknownSVal> ValueToCast =
C.getSVal(CE->getSubExpr()).getAs<DefinedOrUnknownSVal>();
diff --git a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index f23f784016d8..17c813962a23 100644
--- a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -148,7 +148,7 @@ ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
if (!BT)
BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
- BR.emitReport(llvm::make_unique<BugReport>(*BT, Msg, N));
+ BR.emitReport(std::make_unique<PathSensitiveBugReport>(*BT, Msg, N));
return N;
}
@@ -305,7 +305,7 @@ void ExprInspectionChecker::analyzerHashDump(const CallExpr *CE,
const SourceManager &SM = C.getSourceManager();
FullSourceLoc FL(CE->getArg(0)->getBeginLoc(), SM);
std::string HashContent =
- GetIssueString(SM, FL, getCheckName().getName(), "Category",
+ GetIssueString(SM, FL, getCheckerName().getName(), "Category",
C.getLocationContext()->getDecl(), Opts);
reportBug(HashContent, C);
diff --git a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
index 94542be7dd7c..b315a8452285 100644
--- a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
@@ -55,7 +55,8 @@ void FixedAddressChecker::checkPreStmt(const BinaryOperator *B,
"Using a fixed address is not portable because that "
"address will probably not be valid in all "
"environments or platforms."));
- auto R = llvm::make_unique<BugReport>(*BT, BT->getDescription(), N);
+ auto R =
+ std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
R->addRange(B->getRHS()->getSourceRange());
C.emitReport(std::move(R));
}
diff --git a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index d3ab98033236..d442b26b3959 100644
--- a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -15,16 +15,18 @@
//===----------------------------------------------------------------------===//
#include "Taint.h"
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "Yaml.h"
#include "clang/AST/Attr.h"
#include "clang/Basic/Builtins.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.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 <climits>
-#include <initializer_list>
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <limits>
#include <utility>
using namespace clang;
@@ -44,14 +46,51 @@ public:
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
- void printState(raw_ostream &Out, ProgramStateRef State,
- const char *NL, const char *Sep) const override;
+ void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
+ const char *Sep) const override;
-private:
- static const unsigned InvalidArgIndex = UINT_MAX;
+ using ArgVector = SmallVector<unsigned, 2>;
+ using SignedArgVector = SmallVector<int, 2>;
+
+ enum class VariadicType { None, Src, Dst };
+
+ /// Used to parse the configuration file.
+ struct TaintConfiguration {
+ using NameArgsPair = std::pair<std::string, ArgVector>;
+
+ struct Propagation {
+ std::string Name;
+ ArgVector SrcArgs;
+ SignedArgVector DstArgs;
+ VariadicType VarType;
+ unsigned VarIndex;
+ };
+
+ std::vector<Propagation> Propagations;
+ std::vector<NameArgsPair> Filters;
+ std::vector<NameArgsPair> Sinks;
+
+ TaintConfiguration() = default;
+ TaintConfiguration(const TaintConfiguration &) = default;
+ TaintConfiguration(TaintConfiguration &&) = default;
+ TaintConfiguration &operator=(const TaintConfiguration &) = default;
+ TaintConfiguration &operator=(TaintConfiguration &&) = default;
+ };
+
+ /// Convert SignedArgVector to ArgVector.
+ ArgVector convertToArgVector(CheckerManager &Mgr, const std::string &Option,
+ SignedArgVector Args);
+
+ /// Parse the config.
+ void parseConfiguration(CheckerManager &Mgr, const std::string &Option,
+ TaintConfiguration &&Config);
+
+ static const unsigned InvalidArgIndex{std::numeric_limits<unsigned>::max()};
/// Denotes the return vale.
- static const unsigned ReturnValueIndex = UINT_MAX - 1;
+ static const unsigned ReturnValueIndex{std::numeric_limits<unsigned>::max() -
+ 1};
+private:
mutable std::unique_ptr<BugType> BT;
void initBugType() const {
if (!BT)
@@ -76,28 +115,43 @@ private:
static Optional<SVal> getPointedToSVal(CheckerContext &C, const Expr *Arg);
/// Check for CWE-134: Uncontrolled Format String.
- static const char MsgUncontrolledFormatString[];
+ static constexpr llvm::StringLiteral MsgUncontrolledFormatString =
+ "Untrusted data is used as a format string "
+ "(CWE-134: Uncontrolled Format String)";
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[];
+ static constexpr llvm::StringLiteral MsgSanitizeSystemArgs =
+ "Untrusted data is passed to a system call "
+ "(CERT/STR02-C. Sanitize data passed to complex subsystems)";
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[];
+ static constexpr llvm::StringLiteral 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)";
bool checkTaintedBufferSize(const CallExpr *CE, const FunctionDecl *FDecl,
CheckerContext &C) const;
+ /// Check if tainted data is used as a custom sink's parameter.
+ static constexpr llvm::StringLiteral MsgCustomSink =
+ "Untrusted data is passed to a user-defined sink";
+ bool checkCustomSinks(const CallExpr *CE, StringRef Name,
+ CheckerContext &C) const;
+
/// Generate a report if the expression is tainted or points to tainted data.
- bool generateReportIfTainted(const Expr *E, const char Msg[],
+ bool generateReportIfTainted(const Expr *E, StringRef Msg,
CheckerContext &C) const;
- using ArgVector = SmallVector<unsigned, 2>;
+ struct TaintPropagationRule;
+ using NameRuleMap = llvm::StringMap<TaintPropagationRule>;
+ using NameArgMap = llvm::StringMap<ArgVector>;
/// A struct used to specify taint propagation rules for a function.
///
@@ -109,8 +163,6 @@ private:
/// ReturnValueIndex is added to the dst list, the return value will be
/// tainted.
struct TaintPropagationRule {
- enum class VariadicType { None, Src, Dst };
-
using PropagationFuncType = bool (*)(bool IsTainted, const CallExpr *,
CheckerContext &C);
@@ -131,8 +183,7 @@ private:
: VariadicIndex(InvalidArgIndex), VarType(VariadicType::None),
PropagationFunc(nullptr) {}
- TaintPropagationRule(std::initializer_list<unsigned> &&Src,
- std::initializer_list<unsigned> &&Dst,
+ TaintPropagationRule(ArgVector &&Src, ArgVector &&Dst,
VariadicType Var = VariadicType::None,
unsigned VarIndex = InvalidArgIndex,
PropagationFuncType Func = nullptr)
@@ -141,7 +192,8 @@ private:
/// Get the propagation rule for a given function.
static TaintPropagationRule
- getTaintPropagationRule(const FunctionDecl *FDecl, StringRef Name,
+ getTaintPropagationRule(const NameRuleMap &CustomPropagations,
+ const FunctionDecl *FDecl, StringRef Name,
CheckerContext &C);
void addSrcArg(unsigned A) { SrcArgs.push_back(A); }
@@ -176,25 +228,71 @@ private:
static bool postSocket(bool IsTainted, const CallExpr *CE,
CheckerContext &C);
};
+
+ /// Defines a map between the propagation function's name and
+ /// TaintPropagationRule.
+ NameRuleMap CustomPropagations;
+
+ /// Defines a map between the filter function's name and filtering args.
+ NameArgMap CustomFilters;
+
+ /// Defines a map between the sink function's name and sinking args.
+ NameArgMap CustomSinks;
};
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)";
+// FIXME: these lines can be removed in C++17
+constexpr llvm::StringLiteral GenericTaintChecker::MsgUncontrolledFormatString;
+constexpr llvm::StringLiteral GenericTaintChecker::MsgSanitizeSystemArgs;
+constexpr llvm::StringLiteral GenericTaintChecker::MsgTaintedBufferSize;
+constexpr llvm::StringLiteral GenericTaintChecker::MsgCustomSink;
+} // end of anonymous namespace
-const char GenericTaintChecker::MsgSanitizeSystemArgs[] =
- "Untrusted data is passed to a system call "
- "(CERT/STR02-C. Sanitize data passed to complex subsystems)";
+using TaintConfig = GenericTaintChecker::TaintConfiguration;
-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)";
+LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::Propagation)
+LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::NameArgsPair)
-} // end of anonymous namespace
+namespace llvm {
+namespace yaml {
+template <> struct MappingTraits<TaintConfig> {
+ static void mapping(IO &IO, TaintConfig &Config) {
+ IO.mapOptional("Propagations", Config.Propagations);
+ IO.mapOptional("Filters", Config.Filters);
+ IO.mapOptional("Sinks", Config.Sinks);
+ }
+};
+
+template <> struct MappingTraits<TaintConfig::Propagation> {
+ static void mapping(IO &IO, TaintConfig::Propagation &Propagation) {
+ IO.mapRequired("Name", Propagation.Name);
+ IO.mapOptional("SrcArgs", Propagation.SrcArgs);
+ IO.mapOptional("DstArgs", Propagation.DstArgs);
+ IO.mapOptional("VariadicType", Propagation.VarType,
+ GenericTaintChecker::VariadicType::None);
+ IO.mapOptional("VariadicIndex", Propagation.VarIndex,
+ GenericTaintChecker::InvalidArgIndex);
+ }
+};
+
+template <> struct ScalarEnumerationTraits<GenericTaintChecker::VariadicType> {
+ static void enumeration(IO &IO, GenericTaintChecker::VariadicType &Value) {
+ IO.enumCase(Value, "None", GenericTaintChecker::VariadicType::None);
+ IO.enumCase(Value, "Src", GenericTaintChecker::VariadicType::Src);
+ IO.enumCase(Value, "Dst", GenericTaintChecker::VariadicType::Dst);
+ }
+};
+
+template <> struct MappingTraits<TaintConfig::NameArgsPair> {
+ static void mapping(IO &IO, TaintConfig::NameArgsPair &NameArg) {
+ IO.mapRequired("Name", NameArg.first);
+ IO.mapRequired("Args", NameArg.second);
+ }
+};
+} // namespace yaml
+} // namespace llvm
/// 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
@@ -202,9 +300,46 @@ const char GenericTaintChecker::MsgTaintedBufferSize[] =
/// points to data, which should be tainted on return.
REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned)
+GenericTaintChecker::ArgVector GenericTaintChecker::convertToArgVector(
+ CheckerManager &Mgr, const std::string &Option, SignedArgVector Args) {
+ ArgVector Result;
+ for (int Arg : Args) {
+ if (Arg == -1)
+ Result.push_back(ReturnValueIndex);
+ else if (Arg < -1) {
+ Result.push_back(InvalidArgIndex);
+ Mgr.reportInvalidCheckerOptionValue(
+ this, Option,
+ "an argument number for propagation rules greater or equal to -1");
+ } else
+ Result.push_back(static_cast<unsigned>(Arg));
+ }
+ return Result;
+}
+
+void GenericTaintChecker::parseConfiguration(CheckerManager &Mgr,
+ const std::string &Option,
+ TaintConfiguration &&Config) {
+ for (auto &P : Config.Propagations) {
+ GenericTaintChecker::CustomPropagations.try_emplace(
+ P.Name, std::move(P.SrcArgs),
+ convertToArgVector(Mgr, Option, P.DstArgs), P.VarType, P.VarIndex);
+ }
+
+ for (auto &F : Config.Filters) {
+ GenericTaintChecker::CustomFilters.try_emplace(F.first,
+ std::move(F.second));
+ }
+
+ for (auto &S : Config.Sinks) {
+ GenericTaintChecker::CustomSinks.try_emplace(S.first, std::move(S.second));
+ }
+}
+
GenericTaintChecker::TaintPropagationRule
GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
- const FunctionDecl *FDecl, StringRef Name, CheckerContext &C) {
+ const NameRuleMap &CustomPropagations, const FunctionDecl *FDecl,
+ StringRef Name, CheckerContext &C) {
// TODO: Currently, we might lose precision here: we always mark a return
// value as tainted even if it's just a pointer, pointing to tainted data.
@@ -218,7 +353,8 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
.Case("freopen", TaintPropagationRule({}, {ReturnValueIndex}))
.Case("getch", TaintPropagationRule({}, {ReturnValueIndex}))
.Case("getchar", TaintPropagationRule({}, {ReturnValueIndex}))
- .Case("getchar_unlocked", TaintPropagationRule({}, {ReturnValueIndex}))
+ .Case("getchar_unlocked",
+ TaintPropagationRule({}, {ReturnValueIndex}))
.Case("getenv", TaintPropagationRule({}, {ReturnValueIndex}))
.Case("gets", TaintPropagationRule({}, {0, ReturnValueIndex}))
.Case("scanf", TaintPropagationRule({}, {}, VariadicType::Dst, 1))
@@ -297,6 +433,10 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
// or smart memory copy:
// - memccpy - copying until hitting a special character.
+ auto It = CustomPropagations.find(Name);
+ if (It != CustomPropagations.end())
+ return It->getValue();
+
return TaintPropagationRule();
}
@@ -336,8 +476,8 @@ void GenericTaintChecker::addSourcesPre(const CallExpr *CE,
return;
// First, try generating a propagation rule for this function.
- TaintPropagationRule Rule =
- TaintPropagationRule::getTaintPropagationRule(FDecl, Name, C);
+ TaintPropagationRule Rule = TaintPropagationRule::getTaintPropagationRule(
+ this->CustomPropagations, FDecl, Name, C);
if (!Rule.isNull()) {
State = Rule.process(CE, C);
if (!State)
@@ -409,6 +549,9 @@ bool GenericTaintChecker::checkPre(const CallExpr *CE,
if (checkTaintedBufferSize(CE, FDecl, C))
return true;
+ if (checkCustomSinks(CE, Name, C))
+ return true;
+
return false;
}
@@ -446,7 +589,8 @@ GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE,
bool IsTainted = true;
for (unsigned ArgNum : SrcArgs) {
if (ArgNum >= CE->getNumArgs())
- return State;
+ continue;
+
if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(ArgNum), State, C)))
break;
}
@@ -454,7 +598,7 @@ GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE,
// Check for taint in variadic arguments.
if (!IsTainted && VariadicType::Src == VarType) {
// Check if any of the arguments is tainted
- for (unsigned int i = VariadicIndex; i < CE->getNumArgs(); ++i) {
+ for (unsigned i = VariadicIndex; i < CE->getNumArgs(); ++i) {
if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(i), State, C)))
break;
}
@@ -474,8 +618,10 @@ GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE,
continue;
}
+ if (ArgNum >= CE->getNumArgs())
+ continue;
+
// Mark the given argument.
- assert(ArgNum < CE->getNumArgs());
State = State->add<TaintArgsOnPostVisit>(ArgNum);
}
@@ -485,7 +631,7 @@ GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE,
// 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 = VariadicIndex; i < CE->getNumArgs(); ++i) {
+ for (unsigned i = VariadicIndex; i < CE->getNumArgs(); ++i) {
const Expr *Arg = CE->getArg(i);
// Process pointer argument.
const Type *ArgTy = Arg->getType().getTypePtr();
@@ -550,7 +696,7 @@ bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) {
static bool getPrintfFormatArgumentNum(const CallExpr *CE,
const CheckerContext &C,
- unsigned int &ArgNum) {
+ unsigned &ArgNum) {
// Find if the function contains a format string argument.
// Handles: fprintf, printf, sprintf, snprintf, vfprintf, vprintf, vsprintf,
// vsnprintf, syslog, custom annotated functions.
@@ -572,8 +718,7 @@ static bool getPrintfFormatArgumentNum(const CallExpr *CE,
return false;
}
-bool GenericTaintChecker::generateReportIfTainted(const Expr *E,
- const char Msg[],
+bool GenericTaintChecker::generateReportIfTainted(const Expr *E, StringRef Msg,
CheckerContext &C) const {
assert(E);
@@ -591,9 +736,9 @@ bool GenericTaintChecker::generateReportIfTainted(const Expr *E,
// Generate diagnostic.
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
initBugType();
- auto report = llvm::make_unique<BugReport>(*BT, Msg, N);
+ auto report = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
report->addRange(E->getSourceRange());
- report->addVisitor(llvm::make_unique<TaintBugVisitor>(TaintedSVal));
+ report->addVisitor(std::make_unique<TaintBugVisitor>(TaintedSVal));
C.emitReport(std::move(report));
return true;
}
@@ -603,7 +748,7 @@ bool GenericTaintChecker::generateReportIfTainted(const Expr *E,
bool GenericTaintChecker::checkUncontrolledFormatString(
const CallExpr *CE, CheckerContext &C) const {
// Check if the function contains a format string argument.
- unsigned int ArgNum = 0;
+ unsigned ArgNum = 0;
if (!getPrintfFormatArgumentNum(CE, C, ArgNum))
return false;
@@ -629,9 +774,9 @@ bool GenericTaintChecker::checkSystemCall(const CallExpr *CE, StringRef Name,
.Case("execvP", 0)
.Case("execve", 0)
.Case("dlopen", 0)
- .Default(UINT_MAX);
+ .Default(InvalidArgIndex);
- if (ArgNum == UINT_MAX || CE->getNumArgs() < (ArgNum + 1))
+ if (ArgNum == InvalidArgIndex || CE->getNumArgs() < (ArgNum + 1))
return false;
return generateReportIfTainted(CE->getArg(ArgNum), MsgSanitizeSystemArgs, C);
@@ -676,8 +821,33 @@ bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE,
generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C);
}
-void ento::registerGenericTaintChecker(CheckerManager &mgr) {
- mgr.registerChecker<GenericTaintChecker>();
+bool GenericTaintChecker::checkCustomSinks(const CallExpr *CE, StringRef Name,
+ CheckerContext &C) const {
+ auto It = CustomSinks.find(Name);
+ if (It == CustomSinks.end())
+ return false;
+
+ const GenericTaintChecker::ArgVector &Args = It->getValue();
+ for (unsigned ArgNum : Args) {
+ if (ArgNum >= CE->getNumArgs())
+ continue;
+
+ if (generateReportIfTainted(CE->getArg(ArgNum), MsgCustomSink, C))
+ return true;
+ }
+
+ return false;
+}
+
+void ento::registerGenericTaintChecker(CheckerManager &Mgr) {
+ auto *Checker = Mgr.registerChecker<GenericTaintChecker>();
+ std::string Option{"Config"};
+ StringRef ConfigFile =
+ Mgr.getAnalyzerOptions().getCheckerStringOption(Checker, Option);
+ llvm::Optional<TaintConfig> Config =
+ getConfiguration<TaintConfig>(Mgr, Checker, Option, ConfigFile);
+ if (Config)
+ Checker->parseConfiguration(Mgr, Option, std::move(Config.getValue()));
}
bool ento::shouldRegisterGenericTaintChecker(const LangOptions &LO) {
diff --git a/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp b/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
index e3270f1f7be2..b0d101c88517 100644
--- a/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
@@ -54,9 +54,9 @@ public:
ID.AddPointer(getTag());
}
- virtual std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ virtual PathDiagnosticPieceRef
+ VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
// FIXME: Scan the map once in the visitor's constructor and do a direct
// lookup by region.
@@ -261,7 +261,7 @@ namespace ento {
namespace allocation_state {
std::unique_ptr<BugReporterVisitor> getInnerPointerBRVisitor(SymbolRef Sym) {
- return llvm::make_unique<InnerPointerChecker::InnerPointerBRVisitor>(Sym);
+ return std::make_unique<InnerPointerChecker::InnerPointerBRVisitor>(Sym);
}
const MemRegion *getContainerObjRegion(ProgramStateRef State, SymbolRef Sym) {
@@ -278,15 +278,13 @@ const MemRegion *getContainerObjRegion(ProgramStateRef State, SymbolRef Sym) {
} // end namespace ento
} // end namespace clang
-std::shared_ptr<PathDiagnosticPiece>
-InnerPointerChecker::InnerPointerBRVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &) {
+PathDiagnosticPieceRef InnerPointerChecker::InnerPointerBRVisitor::VisitNode(
+ const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &) {
if (!isSymbolTracked(N->getState(), PtrToBuf) ||
isSymbolTracked(N->getFirstPred()->getState(), PtrToBuf))
return nullptr;
- const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ const Stmt *S = N->getStmtForDiagnostics();
if (!S)
return nullptr;
@@ -301,8 +299,7 @@ InnerPointerChecker::InnerPointerBRVisitor::VisitNode(const ExplodedNode *N,
<< "' obtained here";
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
N->getLocationContext());
- return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true,
- nullptr);
+ return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true);
}
void ento::registerInnerPointerChecker(CheckerManager &Mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp b/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
index 6f1060b5f26d..97ace68569ef 100644
--- a/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
@@ -71,7 +71,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
#include <utility>
@@ -248,7 +248,7 @@ public:
};
DefaultBool ChecksEnabled[CK_NumCheckKinds];
- CheckName CheckNames[CK_NumCheckKinds];
+ CheckerNameRef CheckNames[CK_NumCheckKinds];
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
@@ -356,14 +356,12 @@ bool isZero(ProgramStateRef State, const NonLoc &Val);
IteratorChecker::IteratorChecker() {
OutOfRangeBugType.reset(
- new BugType(this, "Iterator out of range", "Misuse of STL APIs",
- /*SuppressOnSink=*/true));
+ new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
MismatchedBugType.reset(
new BugType(this, "Iterator(s) mismatched", "Misuse of STL APIs",
/*SuppressOnSink=*/true));
InvalidatedBugType.reset(
- new BugType(this, "Iterator invalidated", "Misuse of STL APIs",
- /*SuppressOnSink=*/true));
+ new BugType(this, "Iterator invalidated", "Misuse of STL APIs"));
}
void IteratorChecker::checkPreCall(const CallEvent &Call,
@@ -406,13 +404,15 @@ void IteratorChecker::checkPreCall(const CallEvent &Call,
} else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
// Check for out-of-range incrementions and decrementions
- if (Call.getNumArgs() >= 1) {
+ if (Call.getNumArgs() >= 1 &&
+ Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
InstCall->getCXXThisVal(),
Call.getArgSVal(0));
}
} else {
- if (Call.getNumArgs() >= 2) {
+ if (Call.getNumArgs() >= 2 &&
+ Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(),
Call.getArgSVal(0), Call.getArgSVal(1));
}
@@ -565,7 +565,8 @@ void IteratorChecker::checkPostCall(const CallEvent &Call,
if (Func->isOverloadedOperator()) {
const auto Op = Func->getOverloadedOperator();
if (isAssignmentOperator(Op)) {
- const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call);
+ // Overloaded 'operator=' must be a non-static member function.
+ const auto *InstCall = cast<CXXInstanceCall>(&Call);
if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) {
handleAssign(C, InstCall->getCXXThisVal(), Call.getOriginExpr(),
Call.getArgSVal(0));
@@ -590,14 +591,16 @@ void IteratorChecker::checkPostCall(const CallEvent &Call,
return;
} else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) {
if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
- if (Call.getNumArgs() >= 1) {
+ if (Call.getNumArgs() >= 1 &&
+ Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
Call.getReturnValue(),
InstCall->getCXXThisVal(), Call.getArgSVal(0));
return;
}
} else {
- if (Call.getNumArgs() >= 2) {
+ if (Call.getNumArgs() >= 2 &&
+ Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) {
handleRandomIncrOrDecr(C, Func->getOverloadedOperator(),
Call.getReturnValue(), Call.getArgSVal(0),
Call.getArgSVal(1));
@@ -923,7 +926,7 @@ void IteratorChecker::verifyDereference(CheckerContext &C,
auto State = C.getState();
const auto *Pos = getIteratorPosition(State, Val);
if (Pos && isPastTheEnd(State, *Pos)) {
- auto *N = C.generateNonFatalErrorNode(State);
+ auto *N = C.generateErrorNode(State);
if (!N)
return;
reportOutOfRangeBug("Past-the-end iterator dereferenced.", Val, C, N);
@@ -935,7 +938,7 @@ void IteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val) const {
auto State = C.getState();
const auto *Pos = getIteratorPosition(State, Val);
if (Pos && !Pos->isValid()) {
- auto *N = C.generateNonFatalErrorNode(State);
+ auto *N = C.generateErrorNode(State);
if (!N) {
return;
}
@@ -1043,14 +1046,14 @@ void IteratorChecker::verifyRandomIncrOrDecr(CheckerContext &C,
// The result may be the past-end iterator of the container, but any other
// out of range position is undefined behaviour
if (isAheadOfRange(State, advancePosition(C, Op, *Pos, Value))) {
- auto *N = C.generateNonFatalErrorNode(State);
+ auto *N = C.generateErrorNode(State);
if (!N)
return;
reportOutOfRangeBug("Iterator decremented ahead of its valid range.", LHS,
C, N);
}
if (isBehindPastTheEnd(State, advancePosition(C, Op, *Pos, Value))) {
- auto *N = C.generateNonFatalErrorNode(State);
+ auto *N = C.generateErrorNode(State);
if (!N)
return;
reportOutOfRangeBug("Iterator incremented behind the past-the-end "
@@ -1587,7 +1590,8 @@ IteratorPosition IteratorChecker::advancePosition(CheckerContext &C,
void IteratorChecker::reportOutOfRangeBug(const StringRef &Message,
const SVal &Val, CheckerContext &C,
ExplodedNode *ErrNode) const {
- auto R = llvm::make_unique<BugReport>(*OutOfRangeBugType, Message, ErrNode);
+ auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message,
+ ErrNode);
R->markInteresting(Val);
C.emitReport(std::move(R));
}
@@ -1596,7 +1600,8 @@ void IteratorChecker::reportMismatchedBug(const StringRef &Message,
const SVal &Val1, const SVal &Val2,
CheckerContext &C,
ExplodedNode *ErrNode) const {
- auto R = llvm::make_unique<BugReport>(*MismatchedBugType, Message, ErrNode);
+ auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
+ ErrNode);
R->markInteresting(Val1);
R->markInteresting(Val2);
C.emitReport(std::move(R));
@@ -1606,7 +1611,8 @@ void IteratorChecker::reportMismatchedBug(const StringRef &Message,
const SVal &Val, const MemRegion *Reg,
CheckerContext &C,
ExplodedNode *ErrNode) const {
- auto R = llvm::make_unique<BugReport>(*MismatchedBugType, Message, ErrNode);
+ auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
+ ErrNode);
R->markInteresting(Val);
R->markInteresting(Reg);
C.emitReport(std::move(R));
@@ -1615,7 +1621,8 @@ void IteratorChecker::reportMismatchedBug(const StringRef &Message,
void IteratorChecker::reportInvalidatedBug(const StringRef &Message,
const SVal &Val, CheckerContext &C,
ExplodedNode *ErrNode) const {
- auto R = llvm::make_unique<BugReport>(*InvalidatedBugType, Message, ErrNode);
+ auto R = std::make_unique<PathSensitiveBugReport>(*InvalidatedBugType,
+ Message, ErrNode);
R->markInteresting(Val);
C.emitReport(std::move(R));
}
@@ -2373,12 +2380,10 @@ bool ento::shouldRegisterIteratorModeling(const LangOptions &LO) {
auto *checker = Mgr.getChecker<IteratorChecker>(); \
checker->ChecksEnabled[IteratorChecker::CK_##name] = true; \
checker->CheckNames[IteratorChecker::CK_##name] = \
- Mgr.getCurrentCheckName(); \
+ Mgr.getCurrentCheckerName(); \
} \
\
- bool ento::shouldRegister##name(const LangOptions &LO) { \
- return true; \
- }
+ bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
REGISTER_CHECKER(IteratorRangeChecker)
REGISTER_CHECKER(MismatchedIteratorChecker)
diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
index 2b75f3acc922..0d64fbd6f62e 100644
--- a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
@@ -48,8 +48,8 @@ struct ChecksFilter {
/// Check that all ivars are invalidated.
DefaultBool check_InstanceVariableInvalidation;
- CheckName checkName_MissingInvalidationMethod;
- CheckName checkName_InstanceVariableInvalidation;
+ CheckerNameRef checkName_MissingInvalidationMethod;
+ CheckerNameRef checkName_InstanceVariableInvalidation;
};
class IvarInvalidationCheckerImpl {
@@ -199,7 +199,7 @@ class IvarInvalidationCheckerImpl {
const ObjCIvarDecl *IvarDecl,
const IvarToPropMapTy &IvarToPopertyMap);
- void reportNoInvalidationMethod(CheckName CheckName,
+ void reportNoInvalidationMethod(CheckerNameRef CheckName,
const ObjCIvarDecl *FirstIvarDecl,
const IvarToPropMapTy &IvarToPopertyMap,
const ObjCInterfaceDecl *InterfaceD,
@@ -526,7 +526,7 @@ visit(const ObjCImplementationDecl *ImplD) const {
}
void IvarInvalidationCheckerImpl::reportNoInvalidationMethod(
- CheckName CheckName, const ObjCIvarDecl *FirstIvarDecl,
+ CheckerNameRef CheckName, const ObjCIvarDecl *FirstIvarDecl,
const IvarToPropMapTy &IvarToPopertyMap,
const ObjCInterfaceDecl *InterfaceD, bool MissingDeclaration) const {
SmallString<128> sbuf;
@@ -748,12 +748,10 @@ bool ento::shouldRegisterIvarInvalidationModeling(const LangOptions &LO) {
IvarInvalidationChecker *checker = \
mgr.getChecker<IvarInvalidationChecker>(); \
checker->Filter.check_##name = true; \
- checker->Filter.checkName_##name = mgr.getCurrentCheckName(); \
+ checker->Filter.checkName_##name = mgr.getCurrentCheckerName(); \
} \
\
- bool ento::shouldRegister##name(const LangOptions &LO) { \
- return true; \
- }
+ bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
REGISTER_CHECKER(InstanceVariableInvalidation)
REGISTER_CHECKER(MissingInvalidationMethod)
diff --git a/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
index 46067ecbca99..a81015b6e524 100644
--- a/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
@@ -120,12 +120,12 @@ class NonLocalizedStringBRVisitor final : public BugReporterVisitor {
public:
NonLocalizedStringBRVisitor(const MemRegion *NonLocalizedString)
: NonLocalizedString(NonLocalizedString), Satisfied(false) {
- assert(NonLocalizedString);
+ assert(NonLocalizedString);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
void Profile(llvm::FoldingSetNodeID &ID) const override {
ID.Add(NonLocalizedString);
@@ -761,8 +761,8 @@ void NonLocalizedStringChecker::reportLocalizationError(
return;
// Generate the bug report.
- std::unique_ptr<BugReport> R(new BugReport(
- *BT, "User-facing text should use localized string macro", ErrNode));
+ auto R = std::make_unique<PathSensitiveBugReport>(
+ *BT, "User-facing text should use localized string macro", ErrNode);
if (argumentNumber) {
R->addRange(M.getArgExpr(argumentNumber - 1)->getSourceRange());
} else {
@@ -772,7 +772,7 @@ void NonLocalizedStringChecker::reportLocalizationError(
const MemRegion *StringRegion = S.getAsRegion();
if (StringRegion)
- R->addVisitor(llvm::make_unique<NonLocalizedStringBRVisitor>(StringRegion));
+ R->addVisitor(std::make_unique<NonLocalizedStringBRVisitor>(StringRegion));
C.emitReport(std::move(R));
}
@@ -882,18 +882,17 @@ void NonLocalizedStringChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
void NonLocalizedStringChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
- const Decl *D = Call.getDecl();
- if (D && isa<FunctionDecl>(D)) {
- const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- auto formals = FD->parameters();
- for (unsigned i = 0,
- ei = std::min(unsigned(formals.size()), Call.getNumArgs());
- i != ei; ++i) {
- if (isAnnotatedAsTakingLocalized(formals[i])) {
- auto actual = Call.getArgSVal(i);
- if (hasNonLocalizedState(actual, C)) {
- reportLocalizationError(actual, Call, C, i + 1);
- }
+ const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
+ if (!FD)
+ return;
+
+ auto formals = FD->parameters();
+ for (unsigned i = 0, ei = std::min(static_cast<unsigned>(formals.size()),
+ Call.getNumArgs()); i != ei; ++i) {
+ if (isAnnotatedAsTakingLocalized(formals[i])) {
+ auto actual = Call.getArgSVal(i);
+ if (hasNonLocalizedState(actual, C)) {
+ reportLocalizationError(actual, Call, C, i + 1);
}
}
}
@@ -998,9 +997,10 @@ void NonLocalizedStringChecker::checkPostStmt(const ObjCStringLiteral *SL,
setNonLocalizedState(sv, C);
}
-std::shared_ptr<PathDiagnosticPiece>
+PathDiagnosticPieceRef
NonLocalizedStringBRVisitor::VisitNode(const ExplodedNode *Succ,
- BugReporterContext &BRC, BugReport &BR) {
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
if (Satisfied)
return nullptr;
diff --git a/lib/StaticAnalyzer/Checkers/MIGChecker.cpp b/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
index 6e7776bb484e..d8fd125f4003 100644
--- a/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
@@ -274,7 +274,7 @@ void MIGChecker::checkReturnAux(const ReturnStmt *RS, CheckerContext &C) const {
if (!N)
return;
- auto R = llvm::make_unique<BugReport>(
+ auto R = std::make_unique<PathSensitiveBugReport>(
BT,
"MIG callback fails with error after deallocating argument value. "
"This is a use-after-free vulnerability because the caller will try to "
@@ -282,7 +282,8 @@ void MIGChecker::checkReturnAux(const ReturnStmt *RS, CheckerContext &C) const {
N);
R->addRange(RS->getSourceRange());
- bugreporter::trackExpressionValue(N, RS->getRetValue(), *R, false);
+ bugreporter::trackExpressionValue(N, RS->getRetValue(), *R,
+ bugreporter::TrackingKind::Thorough, false);
C.emitReport(std::move(R));
}
diff --git a/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp b/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp
index b250d3f8795e..bbf2ddec5762 100644
--- a/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp
+++ b/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp
@@ -30,8 +30,8 @@ void MPIBugReporter::reportDoubleNonblocking(
ErrorText = "Double nonblocking on request " +
RequestRegion->getDescriptiveName() + ". ";
- auto Report = llvm::make_unique<BugReport>(*DoubleNonblockingBugType,
- ErrorText, ExplNode);
+ auto Report = std::make_unique<PathSensitiveBugReport>(
+ *DoubleNonblockingBugType, ErrorText, ExplNode);
Report->addRange(MPICallEvent.getSourceRange());
SourceRange Range = RequestRegion->sourceRange();
@@ -39,7 +39,7 @@ void MPIBugReporter::reportDoubleNonblocking(
if (Range.isValid())
Report->addRange(Range);
- Report->addVisitor(llvm::make_unique<RequestNodeVisitor>(
+ Report->addVisitor(std::make_unique<RequestNodeVisitor>(
RequestRegion, "Request is previously used by nonblocking call here. "));
Report->markInteresting(RequestRegion);
@@ -53,13 +53,13 @@ void MPIBugReporter::reportMissingWait(
std::string ErrorText{"Request " + RequestRegion->getDescriptiveName() +
" has no matching wait. "};
- auto Report =
- llvm::make_unique<BugReport>(*MissingWaitBugType, ErrorText, ExplNode);
+ auto Report = std::make_unique<PathSensitiveBugReport>(*MissingWaitBugType,
+ ErrorText, ExplNode);
SourceRange Range = RequestRegion->sourceRange();
if (Range.isValid())
Report->addRange(Range);
- Report->addVisitor(llvm::make_unique<RequestNodeVisitor>(
+ Report->addVisitor(std::make_unique<RequestNodeVisitor>(
RequestRegion, "Request is previously used by nonblocking call here. "));
Report->markInteresting(RequestRegion);
@@ -73,8 +73,8 @@ void MPIBugReporter::reportUnmatchedWait(
std::string ErrorText{"Request " + RequestRegion->getDescriptiveName() +
" has no matching nonblocking call. "};
- auto Report =
- llvm::make_unique<BugReport>(*UnmatchedWaitBugType, ErrorText, ExplNode);
+ auto Report = std::make_unique<PathSensitiveBugReport>(*UnmatchedWaitBugType,
+ ErrorText, ExplNode);
Report->addRange(CE.getSourceRange());
SourceRange Range = RequestRegion->sourceRange();
@@ -84,20 +84,22 @@ void MPIBugReporter::reportUnmatchedWait(
BReporter.emitReport(std::move(Report));
}
-std::shared_ptr<PathDiagnosticPiece>
+PathDiagnosticPieceRef
MPIBugReporter::RequestNodeVisitor::VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
- BugReport &BR) {
+ PathSensitiveBugReport &BR) {
if (IsNodeFound)
return nullptr;
const Request *const Req = N->getState()->get<RequestMap>(RequestRegion);
+ assert(Req && "The region must be tracked and alive, given that we've "
+ "just emitted a report against it");
const Request *const PrevReq =
N->getFirstPred()->getState()->get<RequestMap>(RequestRegion);
// Check if request was previously unused or in a different state.
- if ((Req && !PrevReq) || (Req->CurrentState != PrevReq->CurrentState)) {
+ if (!PrevReq || (Req->CurrentState != PrevReq->CurrentState)) {
IsNodeFound = true;
ProgramPoint P = N->getFirstPred()->getLocation();
diff --git a/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.h b/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.h
index 6fbc30288655..9871da026b04 100644
--- a/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.h
+++ b/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.h
@@ -89,9 +89,9 @@ private:
ID.AddPointer(RequestRegion);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
private:
const MemRegion *const RequestRegion;
diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 32ba9bc8e2ef..e064ca6bd88f 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -113,11 +113,14 @@ private:
const ExplodedNode *getAllocationNode(const ExplodedNode *N, SymbolRef Sym,
CheckerContext &C) const;
- std::unique_ptr<BugReport> generateAllocatedDataNotReleasedReport(
- const AllocationPair &AP, ExplodedNode *N, CheckerContext &C) const;
+ std::unique_ptr<PathSensitiveBugReport>
+ generateAllocatedDataNotReleasedReport(const AllocationPair &AP,
+ ExplodedNode *N,
+ CheckerContext &C) const;
/// Mark an AllocationPair interesting for diagnostic reporting.
- void markInteresting(BugReport *R, const AllocationPair &AP) const {
+ void markInteresting(PathSensitiveBugReport *R,
+ const AllocationPair &AP) const {
R->markInteresting(AP.first);
R->markInteresting(AP.second->Region);
}
@@ -139,9 +142,9 @@ private:
ID.AddPointer(Sym);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
};
};
}
@@ -236,8 +239,8 @@ void MacOSKeychainAPIChecker::
os << "Deallocator doesn't match the allocator: '"
<< FunctionsToTrack[PDeallocIdx].Name << "' should be used.";
- auto Report = llvm::make_unique<BugReport>(*BT, os.str(), N);
- Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(AP.first));
+ auto Report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
+ Report->addVisitor(std::make_unique<SecKeychainBugVisitor>(AP.first));
Report->addRange(ArgExpr->getSourceRange());
markInteresting(Report.get(), AP);
C.emitReport(std::move(Report));
@@ -280,8 +283,9 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
<< "the allocator: missing a call to '"
<< FunctionsToTrack[DIdx].Name
<< "'.";
- auto Report = llvm::make_unique<BugReport>(*BT, os.str(), N);
- Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(V));
+ auto Report =
+ std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
+ Report->addVisitor(std::make_unique<SecKeychainBugVisitor>(V));
Report->addRange(ArgExpr->getSourceRange());
Report->markInteresting(AS->Region);
C.emitReport(std::move(Report));
@@ -334,7 +338,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
if (!N)
return;
initBugType();
- auto Report = llvm::make_unique<BugReport>(
+ auto Report = std::make_unique<PathSensitiveBugReport>(
*BT, "Trying to free data which has not been allocated.", N);
Report->addRange(ArgExpr->getSourceRange());
if (AS)
@@ -465,7 +469,7 @@ MacOSKeychainAPIChecker::getAllocationNode(const ExplodedNode *N,
return AllocNode;
}
-std::unique_ptr<BugReport>
+std::unique_ptr<PathSensitiveBugReport>
MacOSKeychainAPIChecker::generateAllocatedDataNotReleasedReport(
const AllocationPair &AP, ExplodedNode *N, CheckerContext &C) const {
const ADFunctionInfo &FI = FunctionsToTrack[AP.second->AllocatorIdx];
@@ -480,18 +484,18 @@ MacOSKeychainAPIChecker::generateAllocatedDataNotReleasedReport(
// allocated, and only report a single path.
PathDiagnosticLocation LocUsedForUniqueing;
const ExplodedNode *AllocNode = getAllocationNode(N, AP.first, C);
- const Stmt *AllocStmt = PathDiagnosticLocation::getStmt(AllocNode);
+ const Stmt *AllocStmt = AllocNode->getStmtForDiagnostics();
if (AllocStmt)
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt,
C.getSourceManager(),
AllocNode->getLocationContext());
- auto Report =
- llvm::make_unique<BugReport>(*BT, os.str(), N, LocUsedForUniqueing,
- AllocNode->getLocationContext()->getDecl());
+ auto Report = std::make_unique<PathSensitiveBugReport>(
+ *BT, os.str(), N, LocUsedForUniqueing,
+ AllocNode->getLocationContext()->getDecl());
- Report->addVisitor(llvm::make_unique<SecKeychainBugVisitor>(AP.first));
+ Report->addVisitor(std::make_unique<SecKeychainBugVisitor>(AP.first));
markInteresting(Report.get(), AP);
return Report;
}
@@ -613,9 +617,10 @@ ProgramStateRef MacOSKeychainAPIChecker::checkPointerEscape(
return State;
}
-std::shared_ptr<PathDiagnosticPiece>
+PathDiagnosticPieceRef
MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode(
- const ExplodedNode *N, BugReporterContext &BRC, BugReport &BR) {
+ const ExplodedNode *N, BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
const AllocationState *AS = N->getState()->get<AllocatedData>(Sym);
if (!AS)
return nullptr;
diff --git a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 1c52d20d0991..d964a1668eaa 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -139,7 +139,8 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
BT_dispatchOnce.reset(new BugType(this, "Improper use of 'dispatch_once'",
"API Misuse (Apple)"));
- auto report = llvm::make_unique<BugReport>(*BT_dispatchOnce, os.str(), N);
+ auto report =
+ std::make_unique<PathSensitiveBugReport>(*BT_dispatchOnce, os.str(), N);
report->addRange(CE->getArg(0)->getSourceRange());
C.emitReport(std::move(report));
}
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index a79b34189065..a82449951873 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -6,8 +6,41 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines malloc/free checker, which checks for potential memory
-// leaks, double free, and use-after-free problems.
+// This file defines a variety of memory management related checkers, such as
+// leak, double free, and use-after-free.
+//
+// The following checkers are defined here:
+//
+// * MallocChecker
+// Despite its name, it models all sorts of memory allocations and
+// de- or reallocation, including but not limited to malloc, free,
+// relloc, new, delete. It also reports on a variety of memory misuse
+// errors.
+// Many other checkers interact very closely with this checker, in fact,
+// most are merely options to this one. Other checkers may register
+// MallocChecker, but do not enable MallocChecker's reports (more details
+// to follow around its field, ChecksEnabled).
+// It also has a boolean "Optimistic" checker option, which if set to true
+// will cause the checker to model user defined memory management related
+// functions annotated via the attribute ownership_takes, ownership_holds
+// and ownership_returns.
+//
+// * NewDeleteChecker
+// Enables the modeling of new, new[], delete, delete[] in MallocChecker,
+// and checks for related double-free and use-after-free errors.
+//
+// * NewDeleteLeaksChecker
+// Checks for leaks related to new, new[], delete, delete[].
+// Depends on NewDeleteChecker.
+//
+// * MismatchedDeallocatorChecker
+// Enables checking whether memory is deallocated with the correspending
+// allocation function in MallocChecker, such as malloc() allocated
+// regions are only freed by free(), new by delete, new[] by delete[].
+//
+// InnerPointerChecker interacts very closely with MallocChecker, but unlike
+// the above checkers, it has it's own file, hence the many InnerPointerChecker
+// related headers and non-static functions.
//
//===----------------------------------------------------------------------===//
@@ -37,6 +70,10 @@
using namespace clang;
using namespace ento;
+//===----------------------------------------------------------------------===//
+// The types of allocation we're modeling.
+//===----------------------------------------------------------------------===//
+
namespace {
// Used to check correspondence between allocators and deallocators.
@@ -50,57 +87,88 @@ enum AllocationFamily {
AF_InnerBuffer
};
+struct MemFunctionInfoTy;
+
+} // end of anonymous namespace
+
+/// Determine family of a deallocation expression.
+static AllocationFamily
+getAllocationFamily(const MemFunctionInfoTy &MemFunctionInfo, CheckerContext &C,
+ const Stmt *S);
+
+/// Print names of allocators and deallocators.
+///
+/// \returns true on success.
+static bool printAllocDeallocName(raw_ostream &os, CheckerContext &C,
+ const Expr *E);
+
+/// Print expected name of an allocator based on the deallocator's
+/// family derived from the DeallocExpr.
+static void printExpectedAllocName(raw_ostream &os,
+ const MemFunctionInfoTy &MemFunctionInfo,
+ CheckerContext &C, const Expr *E);
+
+/// Print expected name of a deallocator based on the allocator's
+/// family.
+static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family);
+
+//===----------------------------------------------------------------------===//
+// The state of a symbol, in terms of memory management.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
class RefState {
- enum Kind { // Reference to allocated memory.
- Allocated,
- // Reference to zero-allocated memory.
- AllocatedOfSizeZero,
- // Reference to released/freed memory.
- Released,
- // The responsibility for freeing resources has transferred from
- // this reference. A relinquished symbol should not be freed.
- Relinquished,
- // We are no longer guaranteed to have observed all manipulations
- // of this pointer/memory. For example, it could have been
- // passed as a parameter to an opaque function.
- Escaped
+ enum Kind {
+ // Reference to allocated memory.
+ Allocated,
+ // Reference to zero-allocated memory.
+ AllocatedOfSizeZero,
+ // Reference to released/freed memory.
+ Released,
+ // The responsibility for freeing resources has transferred from
+ // this reference. A relinquished symbol should not be freed.
+ Relinquished,
+ // We are no longer guaranteed to have observed all manipulations
+ // of this pointer/memory. For example, it could have been
+ // passed as a parameter to an opaque function.
+ Escaped
};
const Stmt *S;
- unsigned K : 3; // Kind enum, but stored as a bitfield.
- unsigned Family : 29; // Rest of 32-bit word, currently just an allocation
- // family.
- RefState(Kind k, const Stmt *s, unsigned family)
- : S(s), K(k), Family(family) {
+ Kind K;
+ AllocationFamily Family;
+
+ RefState(Kind k, const Stmt *s, AllocationFamily family)
+ : S(s), K(k), Family(family) {
assert(family != AF_None);
}
+
public:
bool isAllocated() const { return K == Allocated; }
bool isAllocatedOfSizeZero() const { return K == AllocatedOfSizeZero; }
bool isReleased() const { return K == Released; }
bool isRelinquished() const { return K == Relinquished; }
bool isEscaped() const { return K == Escaped; }
- AllocationFamily getAllocationFamily() const {
- return (AllocationFamily)Family;
- }
+ AllocationFamily getAllocationFamily() const { return Family; }
const Stmt *getStmt() const { return S; }
bool operator==(const RefState &X) const {
return K == X.K && S == X.S && Family == X.Family;
}
- static RefState getAllocated(unsigned family, const Stmt *s) {
+ static RefState getAllocated(AllocationFamily family, const Stmt *s) {
return RefState(Allocated, s, family);
}
static RefState getAllocatedOfSizeZero(const RefState *RS) {
return RefState(AllocatedOfSizeZero, RS->getStmt(),
RS->getAllocationFamily());
}
- static RefState getReleased(unsigned family, const Stmt *s) {
+ static RefState getReleased(AllocationFamily family, const Stmt *s) {
return RefState(Released, s, family);
}
- static RefState getRelinquished(unsigned family, const Stmt *s) {
+ static RefState getRelinquished(AllocationFamily family, const Stmt *s) {
return RefState(Relinquished, s, family);
}
static RefState getEscaped(const RefState *RS) {
@@ -113,8 +181,8 @@ public:
ID.AddInteger(Family);
}
- void dump(raw_ostream &OS) const {
- switch (static_cast<Kind>(K)) {
+ LLVM_DUMP_METHOD void dump(raw_ostream &OS) const {
+ switch (K) {
#define CASE(ID) case ID: OS << #ID; break;
CASE(Allocated)
CASE(AllocatedOfSizeZero)
@@ -127,24 +195,62 @@ public:
LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); }
};
-enum ReallocPairKind {
- RPToBeFreedAfterFailure,
- // The symbol has been freed when reallocation failed.
- RPIsFreeOnFailure,
- // The symbol does not need to be freed after reallocation fails.
- RPDoNotTrackAfterFailure
+} // end of anonymous namespace
+
+REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState)
+
+/// Check if the memory associated with this symbol was released.
+static bool isReleased(SymbolRef Sym, CheckerContext &C);
+
+/// Update the RefState to reflect the new memory allocation.
+/// The optional \p RetVal parameter specifies the newly allocated pointer
+/// value; if unspecified, the value of expression \p E is used.
+static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E,
+ ProgramStateRef State,
+ AllocationFamily Family = AF_Malloc,
+ Optional<SVal> RetVal = None);
+
+//===----------------------------------------------------------------------===//
+// The modeling of memory reallocation.
+//
+// The terminology 'toPtr' and 'fromPtr' will be used:
+// toPtr = realloc(fromPtr, 20);
+//===----------------------------------------------------------------------===//
+
+REGISTER_SET_WITH_PROGRAMSTATE(ReallocSizeZeroSymbols, SymbolRef)
+
+namespace {
+
+/// The state of 'fromPtr' after reallocation is known to have failed.
+enum OwnershipAfterReallocKind {
+ // The symbol needs to be freed (e.g.: realloc)
+ OAR_ToBeFreedAfterFailure,
+ // The symbol has been freed (e.g.: reallocf)
+ OAR_FreeOnFailure,
+ // The symbol doesn't have to freed (e.g.: we aren't sure if, how and where
+ // 'fromPtr' was allocated:
+ // void Haha(int *ptr) {
+ // ptr = realloc(ptr, 67);
+ // // ...
+ // }
+ // ).
+ OAR_DoNotTrackAfterFailure
};
-/// \class ReallocPair
-/// Stores information about the symbol being reallocated by a call to
-/// 'realloc' to allow modeling failed reallocation later in the path.
+/// Stores information about the 'fromPtr' symbol after reallocation.
+///
+/// This is important because realloc may fail, and that needs special modeling.
+/// Whether reallocation failed or not will not be known until later, so we'll
+/// store whether upon failure 'fromPtr' will be freed, or needs to be freed
+/// later, etc.
struct ReallocPair {
- // The symbol which realloc reallocated.
+
+ // The 'fromPtr'.
SymbolRef ReallocatedSym;
- ReallocPairKind Kind;
+ OwnershipAfterReallocKind Kind;
- ReallocPair(SymbolRef S, ReallocPairKind K) :
- ReallocatedSym(S), Kind(K) {}
+ ReallocPair(SymbolRef S, OwnershipAfterReallocKind K)
+ : ReallocatedSym(S), Kind(K) {}
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(Kind);
ID.AddPointer(ReallocatedSym);
@@ -155,42 +261,88 @@ struct ReallocPair {
}
};
-typedef std::pair<const ExplodedNode*, const MemRegion*> LeakInfo;
-
-class MallocChecker : public Checker<check::DeadSymbols,
- check::PointerEscape,
- check::ConstPointerEscape,
- check::PreStmt<ReturnStmt>,
- check::EndFunction,
- check::PreCall,
- check::PostStmt<CallExpr>,
- check::PostStmt<CXXNewExpr>,
- check::NewAllocator,
- check::PreStmt<CXXDeleteExpr>,
- check::PostStmt<BlockExpr>,
- check::PostObjCMessage,
- check::Location,
- eval::Assume>
-{
-public:
- MallocChecker()
- : II_alloca(nullptr), II_win_alloca(nullptr), II_malloc(nullptr),
- II_free(nullptr), II_realloc(nullptr), II_calloc(nullptr),
- II_valloc(nullptr), II_reallocf(nullptr), II_strndup(nullptr),
- II_strdup(nullptr), II_win_strdup(nullptr), II_kmalloc(nullptr),
- II_kfree(nullptr), II_if_nameindex(nullptr),
- II_if_freenameindex(nullptr), II_wcsdup(nullptr),
- II_win_wcsdup(nullptr), II_g_malloc(nullptr), II_g_malloc0(nullptr),
- II_g_realloc(nullptr), II_g_try_malloc(nullptr),
- II_g_try_malloc0(nullptr), II_g_try_realloc(nullptr),
- II_g_free(nullptr), II_g_memdup(nullptr), II_g_malloc_n(nullptr),
- II_g_malloc0_n(nullptr), II_g_realloc_n(nullptr),
- II_g_try_malloc_n(nullptr), II_g_try_malloc0_n(nullptr),
- II_g_try_realloc_n(nullptr) {}
+} // end of anonymous namespace
+
+REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair)
+
+//===----------------------------------------------------------------------===//
+// Kinds of memory operations, information about resource managing functions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+enum class MemoryOperationKind { MOK_Allocate, MOK_Free, MOK_Any };
+struct MemFunctionInfoTy {
+ /// The value of the MallocChecker:Optimistic is stored in this variable.
+ ///
/// In pessimistic mode, the checker assumes that it does not know which
/// functions might free the memory.
+ /// In optimistic mode, the checker assumes that all user-defined functions
+ /// which might free a pointer are annotated.
+ DefaultBool ShouldIncludeOwnershipAnnotatedFunctions;
+
+ // TODO: Change these to CallDescription, and get rid of lazy initialization.
+ mutable IdentifierInfo *II_alloca = nullptr, *II_win_alloca = nullptr,
+ *II_malloc = nullptr, *II_free = nullptr,
+ *II_realloc = nullptr, *II_calloc = nullptr,
+ *II_valloc = nullptr, *II_reallocf = nullptr,
+ *II_strndup = nullptr, *II_strdup = nullptr,
+ *II_win_strdup = nullptr, *II_kmalloc = nullptr,
+ *II_if_nameindex = nullptr,
+ *II_if_freenameindex = nullptr, *II_wcsdup = nullptr,
+ *II_win_wcsdup = nullptr, *II_g_malloc = nullptr,
+ *II_g_malloc0 = nullptr, *II_g_realloc = nullptr,
+ *II_g_try_malloc = nullptr,
+ *II_g_try_malloc0 = nullptr,
+ *II_g_try_realloc = nullptr, *II_g_free = nullptr,
+ *II_g_memdup = nullptr, *II_g_malloc_n = nullptr,
+ *II_g_malloc0_n = nullptr, *II_g_realloc_n = nullptr,
+ *II_g_try_malloc_n = nullptr,
+ *II_g_try_malloc0_n = nullptr, *II_kfree = nullptr,
+ *II_g_try_realloc_n = nullptr;
+
+ 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;
+ bool isCMemFunction(const FunctionDecl *FD, ASTContext &C,
+ AllocationFamily Family,
+ MemoryOperationKind MemKind) const;
+
+ /// Tells if the callee is one of the builtin new/delete operators, including
+ /// placement operators and other standard overloads.
+ bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const;
+ ///@}
+};
+
+} // end of anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Definition of the MallocChecker class.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class MallocChecker
+ : public Checker<check::DeadSymbols, check::PointerEscape,
+ check::ConstPointerEscape, check::PreStmt<ReturnStmt>,
+ check::EndFunction, check::PreCall,
+ check::PostStmt<CallExpr>, check::PostStmt<CXXNewExpr>,
+ check::NewAllocator, check::PreStmt<CXXDeleteExpr>,
+ check::PostStmt<BlockExpr>, check::PostObjCMessage,
+ check::Location, eval::Assume> {
+public:
+ MemFunctionInfoTy MemFunctionInfo;
+
+ /// Many checkers are essentially built into this one, so enabling them will
+ /// make MallocChecker perform additional modeling and reporting.
enum CheckKind {
+ /// When a subchecker is enabled but MallocChecker isn't, model memory
+ /// management but do not emit warnings emitted with MallocChecker only
+ /// enabled.
CK_MallocChecker,
CK_NewDeleteChecker,
CK_NewDeleteLeaksChecker,
@@ -199,16 +351,10 @@ public:
CK_NumCheckKinds
};
- enum class MemoryOperationKind {
- MOK_Allocate,
- MOK_Free,
- MOK_Any
- };
-
- DefaultBool IsOptimistic;
+ using LeakInfo = std::pair<const ExplodedNode *, const MemRegion *>;
DefaultBool ChecksEnabled[CK_NumCheckKinds];
- CheckName CheckNames[CK_NumCheckKinds];
+ CheckerNameRef CheckNames[CK_NumCheckKinds];
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
@@ -248,47 +394,9 @@ private:
mutable std::unique_ptr<BugType> BT_MismatchedDealloc;
mutable std::unique_ptr<BugType> BT_OffsetFree[CK_NumCheckKinds];
mutable std::unique_ptr<BugType> BT_UseZerroAllocated[CK_NumCheckKinds];
- mutable IdentifierInfo *II_alloca, *II_win_alloca, *II_malloc, *II_free,
- *II_realloc, *II_calloc, *II_valloc, *II_reallocf,
- *II_strndup, *II_strdup, *II_win_strdup, *II_kmalloc,
- *II_kfree, *II_if_nameindex, *II_if_freenameindex,
- *II_wcsdup, *II_win_wcsdup, *II_g_malloc,
- *II_g_malloc0, *II_g_realloc, *II_g_try_malloc,
- *II_g_try_malloc0, *II_g_try_realloc, *II_g_free,
- *II_g_memdup, *II_g_malloc_n, *II_g_malloc0_n,
- *II_g_realloc_n, *II_g_try_malloc_n,
- *II_g_try_malloc0_n, *II_g_try_realloc_n;
- mutable Optional<uint64_t> KernelZeroFlagVal;
-
- void initIdentifierInfo(ASTContext &C) const;
-
- /// Determine family of a deallocation expression.
- AllocationFamily getAllocationFamily(CheckerContext &C, const Stmt *S) const;
-
- /// Print names of allocators and deallocators.
- ///
- /// \returns true on success.
- bool printAllocDeallocName(raw_ostream &os, CheckerContext &C,
- const Expr *E) const;
-
- /// Print expected name of an allocator based on the deallocator's
- /// family derived from the DeallocExpr.
- void printExpectedAllocName(raw_ostream &os, CheckerContext &C,
- const Expr *DeallocExpr) const;
- /// Print expected name of a deallocator based on the allocator's
- /// family.
- void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) 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;
- bool isCMemFunction(const FunctionDecl *FD,
- ASTContext &C,
- AllocationFamily Family,
- MemoryOperationKind MemKind) const;
- bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const;
- ///@}
+ // TODO: Remove mutable by moving the initializtaion to the registry function.
+ mutable Optional<uint64_t> KernelZeroFlagVal;
/// Process C++ operator new()'s allocation, which is the part of C++
/// new-expression that goes before the constructor.
@@ -296,23 +404,64 @@ private:
SVal Target) const;
/// Perform a zero-allocation check.
- /// The optional \p RetVal parameter specifies the newly allocated pointer
- /// value; if unspecified, the value of expression \p E is used.
- ProgramStateRef ProcessZeroAllocation(CheckerContext &C, const Expr *E,
- const unsigned AllocationSizeArg,
- ProgramStateRef State,
- Optional<SVal> RetVal = None) const;
-
+ ///
+ /// \param [in] E The expression that allocates memory.
+ /// \param [in] IndexOfSizeArg Index of the argument that specifies the size
+ /// of the memory that needs to be allocated. E.g. for malloc, this would be
+ /// 0.
+ /// \param [in] RetVal Specifies the newly allocated pointer value;
+ /// if unspecified, the value of expression \p E is used.
+ static ProgramStateRef ProcessZeroAllocCheck(CheckerContext &C, const Expr *E,
+ const unsigned IndexOfSizeArg,
+ ProgramStateRef State,
+ Optional<SVal> RetVal = None);
+
+ /// Model functions with the ownership_returns attribute.
+ ///
+ /// User-defined function may have the ownership_returns attribute, which
+ /// annotates that the function returns with an object that was allocated on
+ /// the heap, and passes the ownertship to the callee.
+ ///
+ /// void __attribute((ownership_returns(malloc, 1))) *my_malloc(size_t);
+ ///
+ /// It has two parameters:
+ /// - first: name of the resource (e.g. 'malloc')
+ /// - (OPTIONAL) second: size of the allocated region
+ ///
+ /// \param [in] CE The expression that allocates memory.
+ /// \param [in] Att The ownership_returns attribute.
+ /// \param [in] State The \c ProgramState right before allocation.
+ /// \returns The ProgramState right after allocation.
ProgramStateRef MallocMemReturnsAttr(CheckerContext &C,
const CallExpr *CE,
const OwnershipAttr* Att,
ProgramStateRef State) const;
+
+ /// Models memory allocation.
+ ///
+ /// \param [in] CE The expression that allocates memory.
+ /// \param [in] SizeEx Size of the memory that needs to be allocated.
+ /// \param [in] Init The value the allocated memory needs to be initialized.
+ /// with. For example, \c calloc initializes the allocated memory to 0,
+ /// malloc leaves it undefined.
+ /// \param [in] State The \c ProgramState right before allocation.
+ /// \returns The ProgramState right after allocation.
static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
const Expr *SizeEx, SVal Init,
ProgramStateRef State,
AllocationFamily Family = AF_Malloc);
+
+ /// Models memory allocation.
+ ///
+ /// \param [in] CE The expression that allocates memory.
+ /// \param [in] Size Size of the memory that needs to be allocated.
+ /// \param [in] Init The value the allocated memory needs to be initialized.
+ /// with. For example, \c calloc initializes the allocated memory to 0,
+ /// malloc leaves it undefined.
+ /// \param [in] State The \c ProgramState right before allocation.
+ /// \returns The ProgramState right after allocation.
static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
- SVal SizeEx, SVal Init,
+ SVal Size, SVal Init,
ProgramStateRef State,
AllocationFamily Family = AF_Malloc);
@@ -325,54 +474,125 @@ private:
performKernelMalloc(const CallExpr *CE, CheckerContext &C,
const ProgramStateRef &State) const;
- /// Update the RefState to reflect the new memory allocation.
- /// The optional \p RetVal parameter specifies the newly allocated pointer
- /// value; if unspecified, the value of expression \p E is used.
- static ProgramStateRef
- MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,
- AllocationFamily Family = AF_Malloc,
- Optional<SVal> RetVal = None);
-
+ /// Model functions with the ownership_takes and ownership_holds attributes.
+ ///
+ /// User-defined function may have the ownership_takes and/or ownership_holds
+ /// attributes, which annotates that the function frees the memory passed as a
+ /// parameter.
+ ///
+ /// void __attribute((ownership_takes(malloc, 1))) my_free(void *);
+ /// void __attribute((ownership_holds(malloc, 1))) my_hold(void *);
+ ///
+ /// They have two parameters:
+ /// - first: name of the resource (e.g. 'malloc')
+ /// - second: index of the parameter the attribute applies to
+ ///
+ /// \param [in] CE The expression that frees memory.
+ /// \param [in] Att The ownership_takes or ownership_holds attribute.
+ /// \param [in] State The \c ProgramState right before allocation.
+ /// \returns The ProgramState right after deallocation.
ProgramStateRef FreeMemAttr(CheckerContext &C, const CallExpr *CE,
const OwnershipAttr* Att,
ProgramStateRef State) const;
+
+ /// Models memory deallocation.
+ ///
+ /// \param [in] CE The expression that frees memory.
+ /// \param [in] State The \c ProgramState right before allocation.
+ /// \param [in] Num Index of the argument that needs to be freed. This is
+ /// normally 0, but for custom free functions it may be different.
+ /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds
+ /// attribute.
+ /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known
+ /// to have been allocated, or in other words, the symbol to be freed was
+ /// registered as allocated by this checker. In the following case, \c ptr
+ /// isn't known to be allocated.
+ /// void Haha(int *ptr) {
+ /// ptr = realloc(ptr, 67);
+ /// // ...
+ /// }
+ /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function
+ /// we're modeling returns with Null on failure.
+ /// \returns The ProgramState right after deallocation.
ProgramStateRef FreeMemAux(CheckerContext &C, const CallExpr *CE,
- ProgramStateRef state, unsigned Num,
- bool Hold,
- bool &ReleasedAllocated,
+ ProgramStateRef State, unsigned Num, bool Hold,
+ bool &IsKnownToBeAllocated,
bool ReturnsNullOnFailure = false) const;
- ProgramStateRef FreeMemAux(CheckerContext &C, const Expr *Arg,
- const Expr *ParentExpr,
- ProgramStateRef State,
- bool Hold,
- bool &ReleasedAllocated,
+
+ /// Models memory deallocation.
+ ///
+ /// \param [in] ArgExpr The variable who's pointee needs to be freed.
+ /// \param [in] ParentExpr The expression that frees the memory.
+ /// \param [in] State The \c ProgramState right before allocation.
+ /// normally 0, but for custom free functions it may be different.
+ /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds
+ /// attribute.
+ /// \param [out] IsKnownToBeAllocated Whether the memory to be freed is known
+ /// to have been allocated, or in other words, the symbol to be freed was
+ /// registered as allocated by this checker. In the following case, \c ptr
+ /// isn't known to be allocated.
+ /// void Haha(int *ptr) {
+ /// ptr = realloc(ptr, 67);
+ /// // ...
+ /// }
+ /// \param [in] ReturnsNullOnFailure Whether the memory deallocation function
+ /// we're modeling returns with Null on failure.
+ /// \returns The ProgramState right after deallocation.
+ ProgramStateRef FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
+ const Expr *ParentExpr, ProgramStateRef State,
+ bool Hold, bool &IsKnownToBeAllocated,
bool ReturnsNullOnFailure = false) const;
+ // TODO: Needs some refactoring, as all other deallocation modeling
+ // functions are suffering from out parameters and messy code due to how
+ // realloc is handled.
+ //
+ /// Models memory reallocation.
+ ///
+ /// \param [in] CE The expression that reallocated memory
+ /// \param [in] ShouldFreeOnFail Whether if reallocation fails, the supplied
+ /// memory should be freed.
+ /// \param [in] State The \c ProgramState right before reallocation.
+ /// \param [in] SuffixWithN Whether the reallocation function we're modeling
+ /// has an '_n' suffix, such as g_realloc_n.
+ /// \returns The ProgramState right after reallocation.
ProgramStateRef ReallocMemAux(CheckerContext &C, const CallExpr *CE,
- bool FreesMemOnFailure,
- ProgramStateRef State,
+ bool ShouldFreeOnFail, ProgramStateRef State,
bool SuffixWithN = false) const;
+
+ /// Evaluates the buffer size that needs to be allocated.
+ ///
+ /// \param [in] Blocks The amount of blocks that needs to be allocated.
+ /// \param [in] BlockBytes The size of a block.
+ /// \returns The symbolic value of \p Blocks * \p BlockBytes.
static SVal evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
const Expr *BlockBytes);
+
+ /// Models zero initialized array allocation.
+ ///
+ /// \param [in] CE The expression that reallocated memory
+ /// \param [in] State The \c ProgramState right before reallocation.
+ /// \returns The ProgramState right after allocation.
static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State);
- /// Check if the memory associated with this symbol was released.
- bool isReleased(SymbolRef Sym, CheckerContext &C) const;
-
/// See if deallocation happens in a suspicious context. If so, escape the
/// pointers that otherwise would have been deallocated and return true.
bool suppressDeallocationsInSuspiciousContexts(const CallExpr *CE,
CheckerContext &C) const;
+ /// If in \p S \p Sym is used, check whether \p Sym was already freed.
bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
+ /// If in \p S \p Sym is used, check whether \p Sym was allocated as a zero
+ /// sized memory region.
void checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
const Stmt *S) const;
+ /// If in \p S \p Sym is being freed, check whether \p Sym was already freed.
bool checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const;
- /// Check if the function is known free memory, or if it is
+ /// Check if the function is known to free memory, or if it is
/// "interesting" and should be modeled explicitly.
///
/// \param [out] EscapingSymbol A function might not free memory in general,
@@ -386,12 +606,12 @@ private:
ProgramStateRef State,
SymbolRef &EscapingSymbol) const;
- // Implementation of the checkPointerEscape callbacks.
+ /// Implementation of the checkPointerEscape callbacks.
ProgramStateRef checkPointerEscapeAux(ProgramStateRef State,
- const InvalidatedSymbols &Escaped,
- const CallEvent *Call,
- PointerEscapeKind Kind,
- bool(*CheckRefState)(const RefState*)) const;
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind,
+ bool IsConstPointerEscape) const;
// Implementation of the checkPreStmt and checkEndFunction callbacks.
void checkEscapeOnReturn(const ReturnStmt *S, CheckerContext &C) const;
@@ -410,6 +630,7 @@ private:
///@}
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 Expr *DeallocExpr) const;
void ReportFreeAlloca(CheckerContext &C, SVal ArgVal,
@@ -435,143 +656,142 @@ private:
/// 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;
+ static LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
+ CheckerContext &C);
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 final : public BugReporterVisitor {
- 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;
-
- // A C++ destructor stack frame in which memory was released. Used for
- // miscellaneous false positive suppression.
- const StackFrameContext *ReleaseDestructorLC;
-
- bool IsLeak;
-
- public:
- MallocBugVisitor(SymbolRef S, bool isLeak = false)
- : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr),
- ReleaseDestructorLC(nullptr), IsLeak(isLeak) {}
-
- static void *getTag() {
- static int Tag = 0;
- return &Tag;
- }
+//===----------------------------------------------------------------------===//
+// Definition of MallocBugVisitor.
+//===----------------------------------------------------------------------===//
- void Profile(llvm::FoldingSetNodeID &ID) const override {
- ID.AddPointer(getTag());
- ID.AddPointer(Sym);
- }
+/// 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 final : public BugReporterVisitor {
+protected:
+ enum NotificationMode { Normal, ReallocationFailed };
- 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) || isa<CXXNewExpr>(Stmt)) &&
- (S && (S->isAllocated() || S->isAllocatedOfSizeZero())) &&
- (!SPrev || !(SPrev->isAllocated() ||
- SPrev->isAllocatedOfSizeZero())));
- }
+ // The allocated region symbol tracked by the main analysis.
+ SymbolRef Sym;
- inline bool isReleased(const RefState *S, const RefState *SPrev,
- const Stmt *Stmt) {
- // Did not track -> released. Other state (allocated) -> released.
- // The statement associated with the release might be missing.
- bool IsReleased = (S && S->isReleased()) &&
- (!SPrev || !SPrev->isReleased());
- assert(!IsReleased ||
- (Stmt && (isa<CallExpr>(Stmt) || isa<CXXDeleteExpr>(Stmt))) ||
- (!Stmt && S->getAllocationFamily() == AF_InnerBuffer));
- return IsReleased;
- }
+ // The mode we are in, i.e. what kind of diagnostics will be emitted.
+ NotificationMode Mode;
- inline bool isRelinquished(const RefState *S, const RefState *SPrev,
- const Stmt *Stmt) {
- // Did not track -> relinquished. Other state (allocated) -> relinquished.
- return (Stmt && (isa<CallExpr>(Stmt) || isa<ObjCMessageExpr>(Stmt) ||
- isa<ObjCPropertyRefExpr>(Stmt)) &&
- (S && S->isRelinquished()) &&
- (!SPrev || !SPrev->isRelinquished()));
- }
+ // A symbol from when the primary region should have been reallocated.
+ SymbolRef FailedReallocSymbol;
- 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() || S->isAllocatedOfSizeZero())) &&
- (SPrev && !(SPrev->isAllocated() ||
- SPrev->isAllocatedOfSizeZero())));
- }
+ // A C++ destructor stack frame in which memory was released. Used for
+ // miscellaneous false positive suppression.
+ const StackFrameContext *ReleaseDestructorLC;
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ bool IsLeak;
- std::shared_ptr<PathDiagnosticPiece>
- getEndPath(BugReporterContext &BRC, const ExplodedNode *EndPathNode,
- BugReport &BR) override {
- if (!IsLeak)
- return nullptr;
+public:
+ MallocBugVisitor(SymbolRef S, bool isLeak = false)
+ : Sym(S), Mode(Normal), FailedReallocSymbol(nullptr),
+ ReleaseDestructorLC(nullptr), IsLeak(isLeak) {}
+
+ static void *getTag() {
+ static int Tag = 0;
+ return &Tag;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const override {
+ ID.AddPointer(getTag());
+ ID.AddPointer(Sym);
+ }
+
+ /// Did not track -> allocated. Other state (released) -> allocated.
+ static inline bool isAllocated(const RefState *RSCurr, const RefState *RSPrev,
+ const Stmt *Stmt) {
+ return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXNewExpr>(Stmt)) &&
+ (RSCurr &&
+ (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
+ (!RSPrev ||
+ !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
+ }
+
+ /// Did not track -> released. Other state (allocated) -> released.
+ /// The statement associated with the release might be missing.
+ static inline bool isReleased(const RefState *RSCurr, const RefState *RSPrev,
+ const Stmt *Stmt) {
+ bool IsReleased =
+ (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
+ assert(!IsReleased ||
+ (Stmt && (isa<CallExpr>(Stmt) || isa<CXXDeleteExpr>(Stmt))) ||
+ (!Stmt && RSCurr->getAllocationFamily() == AF_InnerBuffer));
+ return IsReleased;
+ }
+
+ /// Did not track -> relinquished. Other state (allocated) -> relinquished.
+ static inline bool isRelinquished(const RefState *RSCurr,
+ const RefState *RSPrev, const Stmt *Stmt) {
+ return (Stmt &&
+ (isa<CallExpr>(Stmt) || isa<ObjCMessageExpr>(Stmt) ||
+ isa<ObjCPropertyRefExpr>(Stmt)) &&
+ (RSCurr && RSCurr->isRelinquished()) &&
+ (!RSPrev || !RSPrev->isRelinquished()));
+ }
+
+ /// 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.
+ static inline bool hasReallocFailed(const RefState *RSCurr,
+ const RefState *RSPrev,
+ const Stmt *Stmt) {
+ return ((!Stmt || !isa<CallExpr>(Stmt)) &&
+ (RSCurr &&
+ (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
+ (RSPrev &&
+ !(RSPrev->isAllocated() || RSPrev->isAllocatedOfSizeZero())));
+ }
+
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
+
+ PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *EndPathNode,
+ PathSensitiveBugReport &BR) override {
+ if (!IsLeak)
+ return nullptr;
- PathDiagnosticLocation L =
- PathDiagnosticLocation::createEndOfPath(EndPathNode,
- BRC.getSourceManager());
- // Do not add the statement itself as a range in case of leak.
- return std::make_shared<PathDiagnosticEventPiece>(L, BR.getDescription(),
- false);
- }
+ PathDiagnosticLocation L = BR.getLocation();
+ // Do not add the statement itself as a range in case of leak.
+ return std::make_shared<PathDiagnosticEventPiece>(L, BR.getDescription(),
+ false);
+ }
- private:
- class StackHintGeneratorForReallocationFailed
- : public StackHintGeneratorForSymbol {
- public:
- StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)
+private:
+ class StackHintGeneratorForReallocationFailed
+ : public StackHintGeneratorForSymbol {
+ public:
+ StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M)
: StackHintGeneratorForSymbol(S, M) {}
- std::string getMessageForArg(const Expr *ArgE,
- unsigned ArgIndex) override {
- // Printed parameters start at 1, not 0.
- ++ArgIndex;
+ std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) override {
+ // Printed parameters start at 1, not 0.
+ ++ArgIndex;
- SmallString<200> buf;
- llvm::raw_svector_ostream os(buf);
+ SmallString<200> buf;
+ llvm::raw_svector_ostream os(buf);
- os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
- << " parameter failed";
+ os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex)
+ << " parameter failed";
- return os.str();
- }
+ return os.str();
+ }
- std::string getMessageForReturn(const CallExpr *CallExpr) override {
- return "Reallocation of returned value failed";
- }
- };
+ std::string getMessageForReturn(const CallExpr *CallExpr) override {
+ return "Reallocation of returned value failed";
+ }
};
};
-} // end anonymous namespace
-REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState)
-REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair)
-REGISTER_SET_WITH_PROGRAMSTATE(ReallocSizeZeroSymbols, SymbolRef)
+} // end anonymous namespace
// A map from the freed symbol to the symbol representing the return value of
// the free function.
@@ -591,7 +811,11 @@ public:
};
} // end anonymous namespace
-void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const {
+//===----------------------------------------------------------------------===//
+// Methods of MemFunctionInfoTy.
+//===----------------------------------------------------------------------===//
+
+void MemFunctionInfoTy::initIdentifierInfo(ASTContext &Ctx) const {
if (II_malloc)
return;
II_alloca = &Ctx.Idents.get("alloca");
@@ -631,7 +855,8 @@ void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const {
II_g_try_realloc_n = &Ctx.Idents.get("g_try_realloc_n");
}
-bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
+bool MemFunctionInfoTy::isMemFunction(const FunctionDecl *FD,
+ ASTContext &C) const {
if (isCMemFunction(FD, C, AF_Malloc, MemoryOperationKind::MOK_Any))
return true;
@@ -647,10 +872,9 @@ bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
return false;
}
-bool MallocChecker::isCMemFunction(const FunctionDecl *FD,
- ASTContext &C,
- AllocationFamily Family,
- MemoryOperationKind MemKind) const {
+bool MemFunctionInfoTy::isCMemFunction(const FunctionDecl *FD, ASTContext &C,
+ AllocationFamily Family,
+ MemoryOperationKind MemKind) const {
if (!FD)
return false;
@@ -703,7 +927,7 @@ bool MallocChecker::isCMemFunction(const FunctionDecl *FD,
if (Family != AF_Malloc)
return false;
- if (IsOptimistic && FD->hasAttrs()) {
+ if (ShouldIncludeOwnershipAnnotatedFunctions && FD->hasAttrs()) {
for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {
OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
if(OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds) {
@@ -718,11 +942,8 @@ bool MallocChecker::isCMemFunction(const FunctionDecl *FD,
return false;
}
-
-// Tells if the callee is one of the builtin new/delete operators, including
-// placement operators and other standard overloads.
-bool MallocChecker::isStandardNewDelete(const FunctionDecl *FD,
- ASTContext &C) const {
+bool MemFunctionInfoTy::isStandardNewDelete(const FunctionDecl *FD,
+ ASTContext &C) const {
if (!FD)
return false;
@@ -738,6 +959,10 @@ bool MallocChecker::isStandardNewDelete(const FunctionDecl *FD,
return !L.isValid() || C.getSourceManager().isInSystemHeader(L);
}
+//===----------------------------------------------------------------------===//
+// Methods of MallocChecker and MallocBugVisitor.
+//===----------------------------------------------------------------------===//
+
llvm::Optional<ProgramStateRef> MallocChecker::performKernelMalloc(
const CallExpr *CE, CheckerContext &C, const ProgramStateRef &State) const {
// 3-argument malloc(), as commonly used in {Free,Net,Open}BSD Kernels:
@@ -836,28 +1061,35 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
return;
ProgramStateRef State = C.getState();
- bool ReleasedAllocatedMemory = false;
+ bool IsKnownToBeAllocatedMemory = false;
if (FD->getKind() == Decl::Function) {
- initIdentifierInfo(C.getASTContext());
+ MemFunctionInfo.initIdentifierInfo(C.getASTContext());
IdentifierInfo *FunI = FD->getIdentifier();
- if (FunI == II_malloc || FunI == II_g_malloc || FunI == II_g_try_malloc) {
- if (CE->getNumArgs() < 1)
+ if (FunI == MemFunctionInfo.II_malloc ||
+ FunI == MemFunctionInfo.II_g_malloc ||
+ FunI == MemFunctionInfo.II_g_try_malloc) {
+ switch (CE->getNumArgs()) {
+ default:
return;
- if (CE->getNumArgs() < 3) {
+ case 1:
+ State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
+ State = ProcessZeroAllocCheck(C, CE, 0, State);
+ break;
+ case 2:
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
- if (CE->getNumArgs() == 1)
- State = ProcessZeroAllocation(C, CE, 0, State);
- } else if (CE->getNumArgs() == 3) {
+ break;
+ case 3:
llvm::Optional<ProgramStateRef> MaybeState =
performKernelMalloc(CE, C, State);
if (MaybeState.hasValue())
State = MaybeState.getValue();
else
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
+ break;
}
- } else if (FunI == II_kmalloc) {
+ } else if (FunI == MemFunctionInfo.II_kmalloc) {
if (CE->getNumArgs() < 1)
return;
llvm::Optional<ProgramStateRef> MaybeState =
@@ -866,100 +1098,116 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
State = MaybeState.getValue();
else
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
- } else if (FunI == II_valloc) {
+ } else if (FunI == MemFunctionInfo.II_valloc) {
if (CE->getNumArgs() < 1)
return;
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State);
- State = ProcessZeroAllocation(C, CE, 0, State);
- } else if (FunI == II_realloc || FunI == II_g_realloc ||
- FunI == II_g_try_realloc) {
- State = ReallocMemAux(C, CE, false, State);
- State = ProcessZeroAllocation(C, CE, 1, State);
- } else if (FunI == II_reallocf) {
- State = ReallocMemAux(C, CE, true, State);
- State = ProcessZeroAllocation(C, CE, 1, State);
- } else if (FunI == II_calloc) {
+ State = ProcessZeroAllocCheck(C, CE, 0, State);
+ } else if (FunI == MemFunctionInfo.II_realloc ||
+ FunI == MemFunctionInfo.II_g_realloc ||
+ FunI == MemFunctionInfo.II_g_try_realloc) {
+ State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ false, State);
+ State = ProcessZeroAllocCheck(C, CE, 1, State);
+ } else if (FunI == MemFunctionInfo.II_reallocf) {
+ State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ true, State);
+ State = ProcessZeroAllocCheck(C, CE, 1, State);
+ } else if (FunI == MemFunctionInfo.II_calloc) {
State = CallocMem(C, CE, State);
- State = ProcessZeroAllocation(C, CE, 0, State);
- State = ProcessZeroAllocation(C, CE, 1, State);
- } else if (FunI == II_free || FunI == II_g_free || FunI == II_kfree) {
+ State = ProcessZeroAllocCheck(C, CE, 0, State);
+ State = ProcessZeroAllocCheck(C, CE, 1, State);
+ } else if (FunI == MemFunctionInfo.II_free ||
+ FunI == MemFunctionInfo.II_g_free ||
+ FunI == MemFunctionInfo.II_kfree) {
if (suppressDeallocationsInSuspiciousContexts(CE, C))
return;
- State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
- } else if (FunI == II_strdup || FunI == II_win_strdup ||
- FunI == II_wcsdup || FunI == II_win_wcsdup) {
+ State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory);
+ } else if (FunI == MemFunctionInfo.II_strdup ||
+ FunI == MemFunctionInfo.II_win_strdup ||
+ FunI == MemFunctionInfo.II_wcsdup ||
+ FunI == MemFunctionInfo.II_win_wcsdup) {
State = MallocUpdateRefState(C, CE, State);
- } else if (FunI == II_strndup) {
+ } else if (FunI == MemFunctionInfo.II_strndup) {
State = MallocUpdateRefState(C, CE, State);
- } else if (FunI == II_alloca || FunI == II_win_alloca) {
+ } else if (FunI == MemFunctionInfo.II_alloca ||
+ FunI == MemFunctionInfo.II_win_alloca) {
if (CE->getNumArgs() < 1)
return;
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
AF_Alloca);
- State = ProcessZeroAllocation(C, CE, 0, State);
- } else if (isStandardNewDelete(FD, C.getASTContext())) {
+ State = ProcessZeroAllocCheck(C, CE, 0, State);
+ } else if (MemFunctionInfo.isStandardNewDelete(FD, C.getASTContext())) {
// Process direct calls to operator new/new[]/delete/delete[] functions
// as distinct from new/new[]/delete/delete[] expressions that are
// processed by the checkPostStmt callbacks for CXXNewExpr and
// CXXDeleteExpr.
- OverloadedOperatorKind K = FD->getOverloadedOperator();
- if (K == OO_New) {
+ switch (FD->getOverloadedOperator()) {
+ case OO_New:
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
AF_CXXNew);
- State = ProcessZeroAllocation(C, CE, 0, State);
- }
- else if (K == OO_Array_New) {
+ State = ProcessZeroAllocCheck(C, CE, 0, State);
+ break;
+ case OO_Array_New:
State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
AF_CXXNewArray);
- State = ProcessZeroAllocation(C, CE, 0, State);
- }
- else if (K == OO_Delete || K == OO_Array_Delete)
- State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
- else
+ State = ProcessZeroAllocCheck(C, CE, 0, State);
+ break;
+ case OO_Delete:
+ case OO_Array_Delete:
+ State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory);
+ break;
+ default:
llvm_unreachable("not a new/delete operator");
- } else if (FunI == II_if_nameindex) {
+ }
+ } else if (FunI == MemFunctionInfo.II_if_nameindex) {
// Should we model this differently? We can allocate a fixed number of
// elements with zeros in the last one.
State = MallocMemAux(C, CE, UnknownVal(), UnknownVal(), State,
AF_IfNameIndex);
- } else if (FunI == II_if_freenameindex) {
- State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
- } else if (FunI == II_g_malloc0 || FunI == II_g_try_malloc0) {
+ } else if (FunI == MemFunctionInfo.II_if_freenameindex) {
+ State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory);
+ } else if (FunI == MemFunctionInfo.II_g_malloc0 ||
+ FunI == MemFunctionInfo.II_g_try_malloc0) {
if (CE->getNumArgs() < 1)
return;
SValBuilder &svalBuilder = C.getSValBuilder();
SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
State = MallocMemAux(C, CE, CE->getArg(0), zeroVal, State);
- State = ProcessZeroAllocation(C, CE, 0, State);
- } else if (FunI == II_g_memdup) {
+ State = ProcessZeroAllocCheck(C, CE, 0, State);
+ } else if (FunI == MemFunctionInfo.II_g_memdup) {
if (CE->getNumArgs() < 2)
return;
State = MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), State);
- State = ProcessZeroAllocation(C, CE, 1, State);
- } else if (FunI == II_g_malloc_n || FunI == II_g_try_malloc_n ||
- FunI == II_g_malloc0_n || FunI == II_g_try_malloc0_n) {
+ State = ProcessZeroAllocCheck(C, CE, 1, State);
+ } else if (FunI == MemFunctionInfo.II_g_malloc_n ||
+ FunI == MemFunctionInfo.II_g_try_malloc_n ||
+ FunI == MemFunctionInfo.II_g_malloc0_n ||
+ FunI == MemFunctionInfo.II_g_try_malloc0_n) {
if (CE->getNumArgs() < 2)
return;
SVal Init = UndefinedVal();
- if (FunI == II_g_malloc0_n || FunI == II_g_try_malloc0_n) {
+ if (FunI == MemFunctionInfo.II_g_malloc0_n ||
+ FunI == MemFunctionInfo.II_g_try_malloc0_n) {
SValBuilder &SB = C.getSValBuilder();
Init = SB.makeZeroVal(SB.getContext().CharTy);
}
SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1));
State = MallocMemAux(C, CE, TotalSize, Init, State);
- State = ProcessZeroAllocation(C, CE, 0, State);
- State = ProcessZeroAllocation(C, CE, 1, State);
- } else if (FunI == II_g_realloc_n || FunI == II_g_try_realloc_n) {
+ State = ProcessZeroAllocCheck(C, CE, 0, State);
+ State = ProcessZeroAllocCheck(C, CE, 1, State);
+ } else if (FunI == MemFunctionInfo.II_g_realloc_n ||
+ FunI == MemFunctionInfo.II_g_try_realloc_n) {
if (CE->getNumArgs() < 3)
return;
- State = ReallocMemAux(C, CE, false, State, true);
- State = ProcessZeroAllocation(C, CE, 1, State);
- State = ProcessZeroAllocation(C, CE, 2, State);
+ State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ false, State,
+ /*SuffixWithN*/ true);
+ State = ProcessZeroAllocCheck(C, CE, 1, State);
+ State = ProcessZeroAllocCheck(C, CE, 2, State);
}
}
- if (IsOptimistic || ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
+ if (MemFunctionInfo.ShouldIncludeOwnershipAnnotatedFunctions ||
+ ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
// Check all the attributes, if there are any.
// There can be multiple of these attributes.
if (FD->hasAttrs())
@@ -979,9 +1227,9 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
}
// Performs a 0-sized allocations check.
-ProgramStateRef MallocChecker::ProcessZeroAllocation(
- CheckerContext &C, const Expr *E, const unsigned AllocationSizeArg,
- ProgramStateRef State, Optional<SVal> RetVal) const {
+ProgramStateRef MallocChecker::ProcessZeroAllocCheck(
+ CheckerContext &C, const Expr *E, const unsigned IndexOfSizeArg,
+ ProgramStateRef State, Optional<SVal> RetVal) {
if (!State)
return nullptr;
@@ -991,7 +1239,7 @@ ProgramStateRef MallocChecker::ProcessZeroAllocation(
const Expr *Arg = nullptr;
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
- Arg = CE->getArg(AllocationSizeArg);
+ Arg = CE->getArg(IndexOfSizeArg);
}
else if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
if (NE->isArray())
@@ -1053,7 +1301,9 @@ static QualType getDeepPointeeType(QualType T) {
return Result;
}
-static bool treatUnusedNewEscaped(const CXXNewExpr *NE) {
+/// \returns true if the constructor invoked by \p NE has an argument of a
+/// pointer/reference to a record type.
+static bool hasNonTrivialConstructorCall(const CXXNewExpr *NE) {
const CXXConstructExpr *ConstructE = NE->getConstructExpr();
if (!ConstructE)
@@ -1083,11 +1333,17 @@ static bool treatUnusedNewEscaped(const CXXNewExpr *NE) {
void MallocChecker::processNewAllocation(const CXXNewExpr *NE,
CheckerContext &C,
SVal Target) const {
- if (!isStandardNewDelete(NE->getOperatorNew(), C.getASTContext()))
+ if (!MemFunctionInfo.isStandardNewDelete(NE->getOperatorNew(),
+ C.getASTContext()))
return;
- ParentMap &PM = C.getLocationContext()->getParentMap();
- if (!PM.isConsumedExpr(NE) && treatUnusedNewEscaped(NE))
+ const ParentMap &PM = C.getLocationContext()->getParentMap();
+
+ // Non-trivial constructors have a chance to escape 'this', but marking all
+ // invocations of trivial constructors as escaped would cause too great of
+ // reduction of true positives, so let's just do that for constructors that
+ // have an argument of a pointer-to-record type.
+ if (!PM.isConsumedExpr(NE) && hasNonTrivialConstructorCall(NE))
return;
ProgramStateRef State = C.getState();
@@ -1098,7 +1354,7 @@ void MallocChecker::processNewAllocation(const CXXNewExpr *NE,
State = MallocUpdateRefState(C, NE, State, NE->isArray() ? AF_CXXNewArray
: AF_CXXNew, Target);
State = addExtentSize(C, NE, State, Target);
- State = ProcessZeroAllocation(C, NE, 0, State, Target);
+ State = ProcessZeroAllocCheck(C, NE, 0, State, Target);
C.addTransition(State);
}
@@ -1132,14 +1388,13 @@ ProgramStateRef MallocChecker::addExtentSize(CheckerContext &C,
// Store the extent size for the (symbolic)region
// containing the elements.
Region = Target.getAsRegion()
- ->getAs<SubRegion>()
+ ->castAs<SubRegion>()
->StripCasts()
- ->getAs<SubRegion>();
+ ->castAs<SubRegion>();
} else {
ElementCount = svalBuilder.makeIntVal(1, true);
- Region = Target.getAsRegion()->getAs<SubRegion>();
+ Region = Target.getAsRegion()->castAs<SubRegion>();
}
- assert(Region);
// Set the region's extent equal to the Size in Bytes.
QualType ElementType = NE->getAllocatedType();
@@ -1167,13 +1422,14 @@ void MallocChecker::checkPreStmt(const CXXDeleteExpr *DE,
if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol())
checkUseAfterFree(Sym, C, DE->getArgument());
- if (!isStandardNewDelete(DE->getOperatorDelete(), C.getASTContext()))
+ if (!MemFunctionInfo.isStandardNewDelete(DE->getOperatorDelete(),
+ C.getASTContext()))
return;
ProgramStateRef State = C.getState();
- bool ReleasedAllocated;
+ bool IsKnownToBeAllocated;
State = FreeMemAux(C, DE->getArgument(), DE, State,
- /*Hold*/false, ReleasedAllocated);
+ /*Hold*/ false, IsKnownToBeAllocated);
C.addTransition(State);
}
@@ -1213,11 +1469,11 @@ void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
if (!*FreeWhenDone)
return;
- bool ReleasedAllocatedMemory;
- ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(0),
- Call.getOriginExpr(), C.getState(),
- /*Hold=*/true, ReleasedAllocatedMemory,
- /*ReturnsNullOnFailure=*/true);
+ bool IsKnownToBeAllocatedMemory;
+ ProgramStateRef State =
+ FreeMemAux(C, Call.getArgExpr(0), Call.getOriginExpr(), C.getState(),
+ /*Hold=*/true, IsKnownToBeAllocatedMemory,
+ /*RetNullOnFailure=*/true);
C.addTransition(State);
}
@@ -1229,7 +1485,7 @@ MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
if (!State)
return nullptr;
- if (Att->getModule() != II_malloc)
+ if (Att->getModule() != MemFunctionInfo.II_malloc)
return nullptr;
OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
@@ -1295,11 +1551,10 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
return MallocUpdateRefState(C, CE, State, Family);
}
-ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C,
- const Expr *E,
- ProgramStateRef State,
- AllocationFamily Family,
- Optional<SVal> RetVal) {
+static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E,
+ ProgramStateRef State,
+ AllocationFamily Family,
+ Optional<SVal> RetVal) {
if (!State)
return nullptr;
@@ -1327,27 +1582,24 @@ ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
if (!State)
return nullptr;
- if (Att->getModule() != II_malloc)
+ if (Att->getModule() != MemFunctionInfo.II_malloc)
return nullptr;
- bool ReleasedAllocated = false;
+ bool IsKnownToBeAllocated = false;
for (const auto &Arg : Att->args()) {
ProgramStateRef StateI = FreeMemAux(
C, CE, State, Arg.getASTIndex(),
- Att->getOwnKind() == OwnershipAttr::Holds, ReleasedAllocated);
+ Att->getOwnKind() == OwnershipAttr::Holds, IsKnownToBeAllocated);
if (StateI)
State = StateI;
}
return State;
}
-ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
- const CallExpr *CE,
- ProgramStateRef State,
- unsigned Num,
- bool Hold,
- bool &ReleasedAllocated,
+ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
+ ProgramStateRef State, unsigned Num,
+ bool Hold, bool &IsKnownToBeAllocated,
bool ReturnsNullOnFailure) const {
if (!State)
return nullptr;
@@ -1355,8 +1607,8 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
if (CE->getNumArgs() < (Num + 1))
return nullptr;
- return FreeMemAux(C, CE->getArg(Num), CE, State, Hold,
- ReleasedAllocated, ReturnsNullOnFailure);
+ return FreeMemAux(C, CE->getArg(Num), CE, State, Hold, IsKnownToBeAllocated,
+ ReturnsNullOnFailure);
}
/// Checks if the previous call to free on the given symbol failed - if free
@@ -1374,8 +1626,10 @@ static bool didPreviousFreeFail(ProgramStateRef State,
return false;
}
-AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C,
- const Stmt *S) const {
+static AllocationFamily
+getAllocationFamily(const MemFunctionInfoTy &MemFunctionInfo, CheckerContext &C,
+ const Stmt *S) {
+
if (!S)
return AF_None;
@@ -1387,10 +1641,11 @@ AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C,
ASTContext &Ctx = C.getASTContext();
- if (isCMemFunction(FD, Ctx, AF_Malloc, MemoryOperationKind::MOK_Any))
+ if (MemFunctionInfo.isCMemFunction(FD, Ctx, AF_Malloc,
+ MemoryOperationKind::MOK_Any))
return AF_Malloc;
- if (isStandardNewDelete(FD, Ctx)) {
+ if (MemFunctionInfo.isStandardNewDelete(FD, Ctx)) {
OverloadedOperatorKind Kind = FD->getOverloadedOperator();
if (Kind == OO_New || Kind == OO_Delete)
return AF_CXXNew;
@@ -1398,10 +1653,12 @@ AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C,
return AF_CXXNewArray;
}
- if (isCMemFunction(FD, Ctx, AF_IfNameIndex, MemoryOperationKind::MOK_Any))
+ if (MemFunctionInfo.isCMemFunction(FD, Ctx, AF_IfNameIndex,
+ MemoryOperationKind::MOK_Any))
return AF_IfNameIndex;
- if (isCMemFunction(FD, Ctx, AF_Alloca, MemoryOperationKind::MOK_Any))
+ if (MemFunctionInfo.isCMemFunction(FD, Ctx, AF_Alloca,
+ MemoryOperationKind::MOK_Any))
return AF_Alloca;
return AF_None;
@@ -1419,8 +1676,8 @@ AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C,
return AF_None;
}
-bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C,
- const Expr *E) const {
+static bool printAllocDeallocName(raw_ostream &os, CheckerContext &C,
+ const Expr *E) {
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
// FIXME: This doesn't handle indirect calls.
const FunctionDecl *FD = CE->getDirectCallee();
@@ -1459,9 +1716,10 @@ bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C,
return false;
}
-void MallocChecker::printExpectedAllocName(raw_ostream &os, CheckerContext &C,
- const Expr *E) const {
- AllocationFamily Family = getAllocationFamily(C, E);
+static void printExpectedAllocName(raw_ostream &os,
+ const MemFunctionInfoTy &MemFunctionInfo,
+ CheckerContext &C, const Expr *E) {
+ AllocationFamily Family = getAllocationFamily(MemFunctionInfo, C, E);
switch(Family) {
case AF_Malloc: os << "malloc()"; return;
@@ -1474,8 +1732,7 @@ void MallocChecker::printExpectedAllocName(raw_ostream &os, CheckerContext &C,
}
}
-void MallocChecker::printExpectedDeallocName(raw_ostream &os,
- AllocationFamily Family) const {
+static void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) {
switch(Family) {
case AF_Malloc: os << "free()"; return;
case AF_CXXNew: os << "'delete'"; return;
@@ -1490,9 +1747,8 @@ void MallocChecker::printExpectedDeallocName(raw_ostream &os,
ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
const Expr *ArgExpr,
const Expr *ParentExpr,
- ProgramStateRef State,
- bool Hold,
- bool &ReleasedAllocated,
+ ProgramStateRef State, bool Hold,
+ bool &IsKnownToBeAllocated,
bool ReturnsNullOnFailure) const {
if (!State)
@@ -1566,6 +1822,9 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
const RefState *RsBase = State->get<RegionState>(SymBase);
SymbolRef PreviousRetStatusSymbol = nullptr;
+ IsKnownToBeAllocated =
+ RsBase && (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero());
+
if (RsBase) {
// Memory returned by alloca() shouldn't be freed.
@@ -1588,7 +1847,8 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
// Check if an expected deallocation function matches the real one.
bool DeallocMatchesAlloc =
- RsBase->getAllocationFamily() == getAllocationFamily(C, ParentExpr);
+ RsBase->getAllocationFamily() ==
+ getAllocationFamily(MemFunctionInfo, C, ParentExpr);
if (!DeallocMatchesAlloc) {
ReportMismatchedDealloc(C, ArgExpr->getSourceRange(),
ParentExpr, RsBase, SymBase, Hold);
@@ -1614,9 +1874,6 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
return nullptr;
}
- ReleasedAllocated = (RsBase != nullptr) && (RsBase->isAllocated() ||
- RsBase->isAllocatedOfSizeZero());
-
// Clean out the info on previous call to free return info.
State = State->remove<FreeReturnValue>(SymBase);
@@ -1631,8 +1888,9 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
}
}
- AllocationFamily Family = RsBase ? RsBase->getAllocationFamily()
- : getAllocationFamily(C, ParentExpr);
+ AllocationFamily Family =
+ RsBase ? RsBase->getAllocationFamily()
+ : getAllocationFamily(MemFunctionInfo, C, ParentExpr);
// Normal free.
if (Hold)
return State->set<RegionState>(SymBase,
@@ -1682,8 +1940,8 @@ Optional<MallocChecker::CheckKind>
MallocChecker::getCheckIfTracked(CheckerContext &C,
const Stmt *AllocDeallocStmt,
bool IsALeakCheck) const {
- return getCheckIfTracked(getAllocationFamily(C, AllocDeallocStmt),
- IsALeakCheck);
+ return getCheckIfTracked(
+ getAllocationFamily(MemFunctionInfo, C, AllocDeallocStmt), IsALeakCheck);
}
Optional<MallocChecker::CheckKind>
@@ -1821,9 +2079,10 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
else
os << "not memory allocated by ";
- printExpectedAllocName(os, C, DeallocExpr);
+ printExpectedAllocName(os, MemFunctionInfo, C, DeallocExpr);
- auto R = llvm::make_unique<BugReport>(*BT_BadFree[*CheckKind], os.str(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
+ os.str(), N);
R->markInteresting(MR);
R->addRange(Range);
C.emitReport(std::move(R));
@@ -1847,7 +2106,7 @@ void MallocChecker::ReportFreeAlloca(CheckerContext &C, SVal ArgVal,
BT_FreeAlloca[*CheckKind].reset(new BugType(
CheckNames[*CheckKind], "Free alloca()", categories::MemoryError));
- auto R = llvm::make_unique<BugReport>(
+ auto R = std::make_unique<PathSensitiveBugReport>(
*BT_FreeAlloca[*CheckKind],
"Memory allocated by alloca() should not be deallocated", N);
R->markInteresting(ArgVal.getAsRegion());
@@ -1903,10 +2162,11 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C,
os << ", not " << DeallocOs.str();
}
- auto R = llvm::make_unique<BugReport>(*BT_MismatchedDealloc, os.str(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT_MismatchedDealloc,
+ os.str(), N);
R->markInteresting(Sym);
R->addRange(Range);
- R->addVisitor(llvm::make_unique<MallocBugVisitor>(Sym));
+ R->addVisitor(std::make_unique<MallocBugVisitor>(Sym));
C.emitReport(std::move(R));
}
}
@@ -1962,7 +2222,8 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
else
os << "allocated memory";
- auto R = llvm::make_unique<BugReport>(*BT_OffsetFree[*CheckKind], os.str(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT_OffsetFree[*CheckKind],
+ os.str(), N);
R->markInteresting(MR->getBaseRegion());
R->addRange(Range);
C.emitReport(std::move(R));
@@ -1988,15 +2249,16 @@ void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range,
AllocationFamily AF =
C.getState()->get<RegionState>(Sym)->getAllocationFamily();
- auto R = llvm::make_unique<BugReport>(*BT_UseFree[*CheckKind],
+ auto R = std::make_unique<PathSensitiveBugReport>(
+ *BT_UseFree[*CheckKind],
AF == AF_InnerBuffer
- ? "Inner pointer of container used after re/deallocation"
- : "Use of memory after it is freed",
+ ? "Inner pointer of container used after re/deallocation"
+ : "Use of memory after it is freed",
N);
R->markInteresting(Sym);
R->addRange(Range);
- R->addVisitor(llvm::make_unique<MallocBugVisitor>(Sym));
+ R->addVisitor(std::make_unique<MallocBugVisitor>(Sym));
if (AF == AF_InnerBuffer)
R->addVisitor(allocation_state::getInnerPointerBRVisitor(Sym));
@@ -2022,7 +2284,7 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
BT_DoubleFree[*CheckKind].reset(new BugType(
CheckNames[*CheckKind], "Double free", categories::MemoryError));
- auto R = llvm::make_unique<BugReport>(
+ auto R = std::make_unique<PathSensitiveBugReport>(
*BT_DoubleFree[*CheckKind],
(Released ? "Attempt to free released memory"
: "Attempt to free non-owned memory"),
@@ -2031,7 +2293,7 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
R->markInteresting(Sym);
if (PrevSym)
R->markInteresting(PrevSym);
- R->addVisitor(llvm::make_unique<MallocBugVisitor>(Sym));
+ R->addVisitor(std::make_unique<MallocBugVisitor>(Sym));
C.emitReport(std::move(R));
}
}
@@ -2051,11 +2313,11 @@ void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const {
"Double delete",
categories::MemoryError));
- auto R = llvm::make_unique<BugReport>(
+ auto R = std::make_unique<PathSensitiveBugReport>(
*BT_DoubleDelete, "Attempt to delete released memory", N);
R->markInteresting(Sym);
- R->addVisitor(llvm::make_unique<MallocBugVisitor>(Sym));
+ R->addVisitor(std::make_unique<MallocBugVisitor>(Sym));
C.emitReport(std::move(R));
}
}
@@ -2079,13 +2341,13 @@ void MallocChecker::ReportUseZeroAllocated(CheckerContext &C,
new BugType(CheckNames[*CheckKind], "Use of zero allocated",
categories::MemoryError));
- auto R = llvm::make_unique<BugReport>(*BT_UseZerroAllocated[*CheckKind],
- "Use of zero-allocated memory", N);
+ auto R = std::make_unique<PathSensitiveBugReport>(
+ *BT_UseZerroAllocated[*CheckKind], "Use of zero-allocated memory", N);
R->addRange(Range);
if (Sym) {
R->markInteresting(Sym);
- R->addVisitor(llvm::make_unique<MallocBugVisitor>(Sym));
+ R->addVisitor(std::make_unique<MallocBugVisitor>(Sym));
}
C.emitReport(std::move(R));
}
@@ -2119,7 +2381,8 @@ void MallocChecker::ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal,
Os << " is a function pointer";
- auto R = llvm::make_unique<BugReport>(*BT_BadFree[*CheckKind], Os.str(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT_BadFree[*CheckKind],
+ Os.str(), N);
R->markInteresting(MR);
R->addRange(Range);
C.emitReport(std::move(R));
@@ -2128,7 +2391,7 @@ void MallocChecker::ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal,
ProgramStateRef MallocChecker::ReallocMemAux(CheckerContext &C,
const CallExpr *CE,
- bool FreesOnFail,
+ bool ShouldFreeOnFail,
ProgramStateRef State,
bool SuffixWithN) const {
if (!State)
@@ -2193,33 +2456,32 @@ ProgramStateRef MallocChecker::ReallocMemAux(CheckerContext &C,
if (!FromPtr || !ToPtr)
return nullptr;
- bool ReleasedAllocated = false;
+ bool IsKnownToBeAllocated = false;
// If the size is 0, free the memory.
if (SizeIsZero)
- if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero, 0,
- false, ReleasedAllocated)){
- // 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. We just free the input pointer and do not add
- // any constrains on the output pointer.
+ // 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. We just free the input pointer and do not add
+ // any constrains on the output pointer.
+ if (ProgramStateRef stateFree =
+ FreeMemAux(C, CE, StateSizeIsZero, 0, false, IsKnownToBeAllocated))
return stateFree;
- }
// Default behavior.
if (ProgramStateRef stateFree =
- FreeMemAux(C, CE, State, 0, false, ReleasedAllocated)) {
+ FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocated)) {
ProgramStateRef stateRealloc = MallocMemAux(C, CE, TotalSize,
UnknownVal(), stateFree);
if (!stateRealloc)
return nullptr;
- ReallocPairKind Kind = RPToBeFreedAfterFailure;
- if (FreesOnFail)
- Kind = RPIsFreeOnFailure;
- else if (!ReleasedAllocated)
- Kind = RPDoNotTrackAfterFailure;
+ OwnershipAfterReallocKind Kind = OAR_ToBeFreedAfterFailure;
+ if (ShouldFreeOnFail)
+ Kind = OAR_FreeOnFailure;
+ else if (!IsKnownToBeAllocated)
+ Kind = OAR_DoNotTrackAfterFailure;
// Record the info about the reallocated symbol so that we could properly
// process failed reallocation.
@@ -2247,9 +2509,9 @@ ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE,
return MallocMemAux(C, CE, TotalSize, zeroVal, State);
}
-LeakInfo
-MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
- CheckerContext &C) const {
+MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N,
+ SymbolRef Sym,
+ CheckerContext &C) {
const LocationContext *LeakContext = N->getLocationContext();
// Walk the ExplodedGraph backwards and find the first node that referred to
// the tracked symbol.
@@ -2329,7 +2591,7 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
const MemRegion *Region = nullptr;
std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);
- const Stmt *AllocationStmt = PathDiagnosticLocation::getStmt(AllocNode);
+ const Stmt *AllocationStmt = AllocNode->getStmtForDiagnostics();
if (AllocationStmt)
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocationStmt,
C.getSourceManager(),
@@ -2344,11 +2606,11 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
os << "Potential memory leak";
}
- auto R = llvm::make_unique<BugReport>(
+ auto R = std::make_unique<PathSensitiveBugReport>(
*BT_Leak[*CheckKind], os.str(), N, LocUsedForUniqueing,
AllocNode->getLocationContext()->getDecl());
R->markInteresting(Sym);
- R->addVisitor(llvm::make_unique<MallocBugVisitor>(Sym, true));
+ R->addVisitor(std::make_unique<MallocBugVisitor>(Sym, true));
C.emitReport(std::move(R));
}
@@ -2430,9 +2692,10 @@ void MallocChecker::checkPreCall(const CallEvent &Call,
ASTContext &Ctx = C.getASTContext();
if (ChecksEnabled[CK_MallocChecker] &&
- (isCMemFunction(FD, Ctx, AF_Malloc, MemoryOperationKind::MOK_Free) ||
- isCMemFunction(FD, Ctx, AF_IfNameIndex,
- MemoryOperationKind::MOK_Free)))
+ (MemFunctionInfo.isCMemFunction(FD, Ctx, AF_Malloc,
+ MemoryOperationKind::MOK_Free) ||
+ MemFunctionInfo.isCMemFunction(FD, Ctx, AF_IfNameIndex,
+ MemoryOperationKind::MOK_Free)))
return;
}
@@ -2535,7 +2798,7 @@ void MallocChecker::checkPostStmt(const BlockExpr *BE,
C.addTransition(state);
}
-bool MallocChecker::isReleased(SymbolRef Sym, CheckerContext &C) const {
+static bool isReleased(SymbolRef Sym, CheckerContext &C) {
assert(Sym);
const RefState *RS = C.getState()->get<RegionState>(Sym);
return (RS && RS->isReleased());
@@ -2640,13 +2903,17 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
SymbolRef ReallocSym = I.getData().ReallocatedSym;
if (const RefState *RS = state->get<RegionState>(ReallocSym)) {
if (RS->isReleased()) {
- if (I.getData().Kind == RPToBeFreedAfterFailure)
+ switch (I.getData().Kind) {
+ case OAR_ToBeFreedAfterFailure:
state = state->set<RegionState>(ReallocSym,
RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
- else if (I.getData().Kind == RPDoNotTrackAfterFailure)
+ break;
+ case OAR_DoNotTrackAfterFailure:
state = state->remove<RegionState>(ReallocSym);
- else
- assert(I.getData().Kind == RPIsFreeOnFailure);
+ break;
+ default:
+ assert(I.getData().Kind == OAR_FreeOnFailure);
+ }
}
}
state = state->remove<ReallocPairs>(I.getKey());
@@ -2729,7 +2996,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
// If it's one of the allocation functions we can reason about, we model
// its behavior explicitly.
- if (isMemFunction(FD, ASTC))
+ if (MemFunctionInfo.isMemFunction(FD, ASTC))
return false;
// If it's not a system call, assume it frees memory.
@@ -2821,35 +3088,32 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
return false;
}
-static bool retTrue(const RefState *RS) {
- return true;
-}
-
-static bool checkIfNewOrNewArrayFamily(const RefState *RS) {
- return (RS->getAllocationFamily() == AF_CXXNewArray ||
- RS->getAllocationFamily() == AF_CXXNew);
-}
-
ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State,
const InvalidatedSymbols &Escaped,
const CallEvent *Call,
PointerEscapeKind Kind) const {
- return checkPointerEscapeAux(State, Escaped, Call, Kind, &retTrue);
+ return checkPointerEscapeAux(State, Escaped, Call, Kind,
+ /*IsConstPointerEscape*/ false);
}
ProgramStateRef MallocChecker::checkConstPointerEscape(ProgramStateRef State,
const InvalidatedSymbols &Escaped,
const CallEvent *Call,
PointerEscapeKind Kind) const {
+ // If a const pointer escapes, it may not be freed(), but it could be deleted.
return checkPointerEscapeAux(State, Escaped, Call, Kind,
- &checkIfNewOrNewArrayFamily);
+ /*IsConstPointerEscape*/ true);
}
-ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State,
- const InvalidatedSymbols &Escaped,
- const CallEvent *Call,
- PointerEscapeKind Kind,
- bool(*CheckRefState)(const RefState*)) const {
+static bool checkIfNewOrNewArrayFamily(const RefState *RS) {
+ return (RS->getAllocationFamily() == AF_CXXNewArray ||
+ RS->getAllocationFamily() == AF_CXXNew);
+}
+
+ProgramStateRef MallocChecker::checkPointerEscapeAux(
+ ProgramStateRef State, const InvalidatedSymbols &Escaped,
+ const CallEvent *Call, PointerEscapeKind Kind,
+ bool IsConstPointerEscape) const {
// If we know that the call does not free memory, or we want to process the
// call later, keep tracking the top level arguments.
SymbolRef EscapingSymbol = nullptr;
@@ -2868,12 +3132,10 @@ ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State,
if (EscapingSymbol && EscapingSymbol != sym)
continue;
- if (const RefState *RS = State->get<RegionState>(sym)) {
- if ((RS->isAllocated() || RS->isAllocatedOfSizeZero()) &&
- CheckRefState(RS)) {
- State = State->set<RegionState>(sym, RefState::getEscaped(RS));
- }
- }
+ if (const RefState *RS = State->get<RegionState>(sym))
+ if (RS->isAllocated() || RS->isAllocatedOfSizeZero())
+ if (!IsConstPointerEscape || checkIfNewOrNewArrayFamily(RS))
+ State = State->set<RegionState>(sym, RefState::getEscaped(RS));
}
return State;
}
@@ -2883,9 +3145,8 @@ static SymbolRef findFailedReallocSymbol(ProgramStateRef currState,
ReallocPairsTy currMap = currState->get<ReallocPairs>();
ReallocPairsTy prevMap = prevState->get<ReallocPairs>();
- for (ReallocPairsTy::iterator I = prevMap.begin(), E = prevMap.end();
- I != E; ++I) {
- SymbolRef sym = I.getKey();
+ for (const ReallocPairsTy::value_type &Pair : prevMap) {
+ SymbolRef sym = Pair.first;
if (!currMap.lookup(sym))
return sym;
}
@@ -2906,19 +3167,19 @@ static bool isReferenceCountingPointerDestructor(const CXXDestructorDecl *DD) {
return false;
}
-std::shared_ptr<PathDiagnosticPiece> MallocChecker::MallocBugVisitor::VisitNode(
- const ExplodedNode *N, BugReporterContext &BRC, BugReport &BR) {
-
+PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
ProgramStateRef state = N->getState();
ProgramStateRef statePrev = N->getFirstPred()->getState();
- const RefState *RS = state->get<RegionState>(Sym);
+ const RefState *RSCurr = state->get<RegionState>(Sym);
const RefState *RSPrev = statePrev->get<RegionState>(Sym);
- const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ const Stmt *S = N->getStmtForDiagnostics();
// When dealing with containers, we sometimes want to give a note
// even if the statement is missing.
- if (!S && (!RS || RS->getAllocationFamily() != AF_InnerBuffer))
+ if (!S && (!RSCurr || RSCurr->getAllocationFamily() != AF_InnerBuffer))
return nullptr;
const LocationContext *CurrentLC = N->getLocationContext();
@@ -2948,17 +3209,17 @@ std::shared_ptr<PathDiagnosticPiece> MallocChecker::MallocBugVisitor::VisitNode(
// Find out if this is an interesting point and what is the kind.
StringRef Msg;
- StackHintGeneratorForSymbol *StackHint = nullptr;
+ std::unique_ptr<StackHintGeneratorForSymbol> StackHint = nullptr;
SmallString<256> Buf;
llvm::raw_svector_ostream OS(Buf);
if (Mode == Normal) {
- if (isAllocated(RS, RSPrev, S)) {
+ if (isAllocated(RSCurr, RSPrev, S)) {
Msg = "Memory is allocated";
- StackHint = new StackHintGeneratorForSymbol(Sym,
- "Returned allocated memory");
- } else if (isReleased(RS, RSPrev, S)) {
- const auto Family = RS->getAllocationFamily();
+ StackHint = std::make_unique<StackHintGeneratorForSymbol>(
+ Sym, "Returned allocated memory");
+ } else if (isReleased(RSCurr, RSPrev, S)) {
+ const auto Family = RSCurr->getAllocationFamily();
switch (Family) {
case AF_Alloca:
case AF_Malloc:
@@ -2966,8 +3227,8 @@ std::shared_ptr<PathDiagnosticPiece> MallocChecker::MallocBugVisitor::VisitNode(
case AF_CXXNewArray:
case AF_IfNameIndex:
Msg = "Memory is released";
- StackHint = new StackHintGeneratorForSymbol(Sym,
- "Returning; memory was released");
+ StackHint = std::make_unique<StackHintGeneratorForSymbol>(
+ Sym, "Returning; memory was released");
break;
case AF_InnerBuffer: {
const MemRegion *ObjRegion =
@@ -2978,11 +3239,11 @@ std::shared_ptr<PathDiagnosticPiece> MallocChecker::MallocBugVisitor::VisitNode(
if (N->getLocation().getKind() == ProgramPoint::PostImplicitCallKind) {
OS << "deallocated by call to destructor";
- StackHint = new StackHintGeneratorForSymbol(Sym,
- "Returning; inner buffer was deallocated");
+ StackHint = std::make_unique<StackHintGeneratorForSymbol>(
+ Sym, "Returning; inner buffer was deallocated");
} else {
OS << "reallocated by call to '";
- const Stmt *S = RS->getStmt();
+ const Stmt *S = RSCurr->getStmt();
if (const auto *MemCallE = dyn_cast<CXXMemberCallExpr>(S)) {
OS << MemCallE->getMethodDecl()->getNameAsString();
} else if (const auto *OpCallE = dyn_cast<CXXOperatorCallExpr>(S)) {
@@ -2994,8 +3255,8 @@ std::shared_ptr<PathDiagnosticPiece> MallocChecker::MallocBugVisitor::VisitNode(
OS << (D ? D->getNameAsString() : "unknown");
}
OS << "'";
- StackHint = new StackHintGeneratorForSymbol(Sym,
- "Returning; inner buffer was reallocated");
+ StackHint = std::make_unique<StackHintGeneratorForSymbol>(
+ Sym, "Returning; inner buffer was reallocated");
}
Msg = OS.str();
break;
@@ -3033,14 +3294,14 @@ std::shared_ptr<PathDiagnosticPiece> MallocChecker::MallocBugVisitor::VisitNode(
}
}
}
- } else if (isRelinquished(RS, RSPrev, S)) {
+ } else if (isRelinquished(RSCurr, RSPrev, S)) {
Msg = "Memory ownership is transferred";
- StackHint = new StackHintGeneratorForSymbol(Sym, "");
- } else if (isReallocFailedCheck(RS, RSPrev, S)) {
+ StackHint = std::make_unique<StackHintGeneratorForSymbol>(Sym, "");
+ } else if (hasReallocFailed(RSCurr, RSPrev, S)) {
Mode = ReallocationFailed;
Msg = "Reallocation failed";
- StackHint = new StackHintGeneratorForReallocationFailed(Sym,
- "Reallocation failed");
+ StackHint = std::make_unique<StackHintGeneratorForReallocationFailed>(
+ Sym, "Reallocation failed");
if (SymbolRef sym = findFailedReallocSymbol(state, statePrev)) {
// Is it possible to fail two reallocs WITHOUT testing in between?
@@ -3059,21 +3320,24 @@ std::shared_ptr<PathDiagnosticPiece> MallocChecker::MallocBugVisitor::VisitNode(
if (!statePrev->get<RegionState>(FailedReallocSymbol)) {
// We're at the reallocation point.
Msg = "Attempt to reallocate memory";
- StackHint = new StackHintGeneratorForSymbol(Sym,
- "Returned reallocated memory");
+ StackHint = std::make_unique<StackHintGeneratorForSymbol>(
+ Sym, "Returned reallocated memory");
FailedReallocSymbol = nullptr;
Mode = Normal;
}
}
- if (Msg.empty())
+ if (Msg.empty()) {
+ assert(!StackHint);
return nullptr;
+ }
+
assert(StackHint);
// Generate the extra diagnostic.
PathDiagnosticLocation Pos;
if (!S) {
- assert(RS->getAllocationFamily() == AF_InnerBuffer);
+ assert(RSCurr->getAllocationFamily() == AF_InnerBuffer);
auto PostImplCall = N->getLocation().getAs<PostImplicitCall>();
if (!PostImplCall)
return nullptr;
@@ -3084,7 +3348,9 @@ std::shared_ptr<PathDiagnosticPiece> MallocChecker::MallocBugVisitor::VisitNode(
N->getLocationContext());
}
- return std::make_shared<PathDiagnosticEventPiece>(Pos, Msg, true, StackHint);
+ auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, Msg, true);
+ BR.addCallStackHint(P, std::move(StackHint));
+ return P;
}
void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
@@ -3131,13 +3397,13 @@ void ento::registerInnerPointerCheckerAux(CheckerManager &mgr) {
MallocChecker *checker = mgr.getChecker<MallocChecker>();
checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] = true;
checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
- mgr.getCurrentCheckName();
+ mgr.getCurrentCheckerName();
}
void ento::registerDynamicMemoryModeling(CheckerManager &mgr) {
auto *checker = mgr.registerChecker<MallocChecker>();
- checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption(
- checker, "Optimistic");
+ checker->MemFunctionInfo.ShouldIncludeOwnershipAnnotatedFunctions =
+ mgr.getAnalyzerOptions().getCheckerBooleanOption(checker, "Optimistic");
}
bool ento::shouldRegisterDynamicMemoryModeling(const LangOptions &LO) {
@@ -3148,12 +3414,11 @@ bool ento::shouldRegisterDynamicMemoryModeling(const LangOptions &LO) {
void ento::register##name(CheckerManager &mgr) { \
MallocChecker *checker = mgr.getChecker<MallocChecker>(); \
checker->ChecksEnabled[MallocChecker::CK_##name] = true; \
- checker->CheckNames[MallocChecker::CK_##name] = mgr.getCurrentCheckName(); \
+ checker->CheckNames[MallocChecker::CK_##name] = \
+ mgr.getCurrentCheckerName(); \
} \
\
- bool ento::shouldRegister##name(const LangOptions &LO) { \
- return true; \
- }
+ bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
REGISTER_CHECKER(MallocChecker)
REGISTER_CHECKER(NewDeleteChecker)
diff --git a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
index 2eb4d7141e28..b5881a9e6533 100644
--- a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
@@ -183,7 +183,7 @@ public:
QualType CastedType = i->CastedExpr->getType();
if (!CastedType->isPointerType())
continue;
- QualType PointeeType = CastedType->getAs<PointerType>()->getPointeeType();
+ QualType PointeeType = CastedType->getPointeeType();
if (PointeeType->isVoidType())
continue;
diff --git a/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp b/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
index 270efede8385..ceea62160545 100644
--- a/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
@@ -67,7 +67,7 @@ void MmapWriteExecChecker::checkPreCall(const CallEvent &Call,
if (!N)
return;
- auto Report = llvm::make_unique<BugReport>(
+ auto Report = std::make_unique<PathSensitiveBugReport>(
*BT, "Both PROT_WRITE and PROT_EXEC flags are set. This can "
"lead to exploitable memory regions, which could be overwritten "
"with malicious code", N);
diff --git a/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index d8a9af78536a..1473c05d7e3f 100644
--- a/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -169,9 +169,9 @@ private:
// in the first place.
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
private:
const MoveChecker &Chk;
@@ -270,9 +270,10 @@ static const MemRegion *unwrapRValueReferenceIndirection(const MemRegion *MR) {
return MR;
}
-std::shared_ptr<PathDiagnosticPiece>
+PathDiagnosticPieceRef
MoveChecker::MovedBugVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC, BugReport &BR) {
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
// We need only the last move of the reported object's region.
// The visitor walks the ExplodedGraph backwards.
if (Found)
@@ -288,7 +289,7 @@ MoveChecker::MovedBugVisitor::VisitNode(const ExplodedNode *N,
return nullptr;
// Retrieve the associated statement.
- const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ const Stmt *S = N->getStmtForDiagnostics();
if (!S)
return nullptr;
Found = true;
@@ -400,7 +401,7 @@ ExplodedNode *MoveChecker::reportBug(const MemRegion *Region,
PathDiagnosticLocation LocUsedForUniqueing;
const ExplodedNode *MoveNode = getMoveLocation(N, Region, C);
- if (const Stmt *MoveStmt = PathDiagnosticLocation::getStmt(MoveNode))
+ if (const Stmt *MoveStmt = MoveNode->getStmtForDiagnostics())
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
MoveStmt, C.getSourceManager(), MoveNode->getLocationContext());
@@ -428,10 +429,10 @@ ExplodedNode *MoveChecker::reportBug(const MemRegion *Region,
break;
}
- auto R =
- llvm::make_unique<BugReport>(*BT, OS.str(), N, LocUsedForUniqueing,
- MoveNode->getLocationContext()->getDecl());
- R->addVisitor(llvm::make_unique<MovedBugVisitor>(*this, Region, RD, MK));
+ auto R = std::make_unique<PathSensitiveBugReport>(
+ *BT, OS.str(), N, LocUsedForUniqueing,
+ MoveNode->getLocationContext()->getDecl());
+ R->addVisitor(std::make_unique<MovedBugVisitor>(*this, Region, RD, MK));
C.emitReport(std::move(R));
return N;
}
diff --git a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index 6fc7c17bc42f..41b7fe5e43b6 100644
--- a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
@@ -67,9 +67,11 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
return;
}
- auto Report = llvm::make_unique<BugReport>(
- *BT, "Use -drain instead of -release when using NSAutoreleasePool and "
- "garbage collection", N);
+ auto Report = std::make_unique<PathSensitiveBugReport>(
+ *BT,
+ "Use -drain instead of -release when using NSAutoreleasePool and "
+ "garbage collection",
+ N);
Report->addRange(msg.getSourceRange());
C.emitReport(std::move(Report));
}
diff --git a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 5cec012258c1..85370bf133cd 100644
--- a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -273,7 +273,8 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const {
CFBT.reset(new CFErrorDerefBug(this));
bug = CFBT.get();
}
- BR.emitReport(llvm::make_unique<BugReport>(*bug, os.str(), event.SinkNode));
+ BR.emitReport(
+ std::make_unique<PathSensitiveBugReport>(*bug, os.str(), event.SinkNode));
}
static bool IsNSError(QualType T, IdentifierInfo *II) {
diff --git a/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
index bf6b3e3e87cf..6ffc89745365 100644
--- a/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
@@ -35,9 +35,11 @@ public:
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
- std::unique_ptr<BugReport>
- genReportNullAttrNonNull(const ExplodedNode *ErrorN, const Expr *ArgE) const;
- std::unique_ptr<BugReport>
+ std::unique_ptr<PathSensitiveBugReport>
+ genReportNullAttrNonNull(const ExplodedNode *ErrorN,
+ const Expr *ArgE,
+ unsigned IdxOfArg) const;
+ std::unique_ptr<PathSensitiveBugReport>
genReportReferenceToNullPointer(const ExplodedNode *ErrorN,
const Expr *ArgE) const;
};
@@ -143,7 +145,7 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call,
std::unique_ptr<BugReport> R;
if (haveAttrNonNull)
- R = genReportNullAttrNonNull(errorNode, ArgE);
+ R = genReportNullAttrNonNull(errorNode, ArgE, idx + 1);
else if (haveRefTypeParam)
R = genReportReferenceToNullPointer(errorNode, ArgE);
@@ -177,9 +179,10 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call,
C.addTransition(state);
}
-std::unique_ptr<BugReport>
+std::unique_ptr<PathSensitiveBugReport>
NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
- const Expr *ArgE) const {
+ const Expr *ArgE,
+ unsigned IdxOfArg) const {
// Lazily allocate the BugType object if it hasn't already been
// created. Ownership is transferred to the BugReporter object once
// the BugReport is passed to 'EmitWarning'.
@@ -187,21 +190,27 @@ NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
BTAttrNonNull.reset(new BugType(
this, "Argument with 'nonnull' attribute passed null", "API"));
- auto R = llvm::make_unique<BugReport>(
- *BTAttrNonNull,
- "Null pointer passed as an argument to a 'nonnull' parameter", ErrorNode);
+ llvm::SmallString<256> SBuf;
+ llvm::raw_svector_ostream OS(SBuf);
+ OS << "Null pointer passed to "
+ << IdxOfArg << llvm::getOrdinalSuffix(IdxOfArg)
+ << " parameter expecting 'nonnull'";
+
+ auto R =
+ std::make_unique<PathSensitiveBugReport>(*BTAttrNonNull, SBuf, ErrorNode);
if (ArgE)
bugreporter::trackExpressionValue(ErrorNode, ArgE, *R);
return R;
}
-std::unique_ptr<BugReport> NonNullParamChecker::genReportReferenceToNullPointer(
+std::unique_ptr<PathSensitiveBugReport>
+NonNullParamChecker::genReportReferenceToNullPointer(
const ExplodedNode *ErrorNode, const Expr *ArgE) const {
if (!BTNullRefArg)
BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer"));
- auto R = llvm::make_unique<BugReport>(
+ auto R = std::make_unique<PathSensitiveBugReport>(
*BTNullRefArg, "Forming reference to null pointer", ErrorNode);
if (ArgE) {
const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
diff --git a/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index af21c84b995b..4322ac207112 100644
--- a/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -112,11 +112,11 @@ public:
DefaultBool CheckNullablePassedToNonnull;
DefaultBool CheckNullableReturnedFromNonnull;
- CheckName CheckNameNullPassedToNonnull;
- CheckName CheckNameNullReturnedFromNonnull;
- CheckName CheckNameNullableDereferenced;
- CheckName CheckNameNullablePassedToNonnull;
- CheckName CheckNameNullableReturnedFromNonnull;
+ CheckerNameRef CheckNameNullPassedToNonnull;
+ CheckerNameRef CheckNameNullReturnedFromNonnull;
+ CheckerNameRef CheckNameNullableDereferenced;
+ CheckerNameRef CheckNameNullablePassedToNonnull;
+ CheckerNameRef CheckNameNullableReturnedFromNonnull;
};
NullabilityChecksFilter Filter;
@@ -137,9 +137,9 @@ private:
ID.AddPointer(Region);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
private:
// The tracked region.
@@ -163,10 +163,10 @@ private:
if (!BT)
BT.reset(new BugType(this, "Nullability", categories::MemoryError));
- auto R = llvm::make_unique<BugReport>(*BT, Msg, N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
if (Region) {
R->markInteresting(Region);
- R->addVisitor(llvm::make_unique<NullabilityBugVisitor>(Region));
+ R->addVisitor(std::make_unique<NullabilityBugVisitor>(Region));
}
if (ValueExpr) {
R->addRange(ValueExpr->getSourceRange());
@@ -290,10 +290,9 @@ NullabilityChecker::getTrackRegion(SVal Val, bool CheckSuperRegion) const {
return dyn_cast<SymbolicRegion>(Region);
}
-std::shared_ptr<PathDiagnosticPiece>
-NullabilityChecker::NullabilityBugVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) {
+PathDiagnosticPieceRef NullabilityChecker::NullabilityBugVisitor::VisitNode(
+ const ExplodedNode *N, BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
ProgramStateRef State = N->getState();
ProgramStateRef StatePrev = N->getFirstPred()->getState();
@@ -310,7 +309,7 @@ NullabilityChecker::NullabilityBugVisitor::VisitNode(const ExplodedNode *N,
// Retrieve the associated statement.
const Stmt *S = TrackedNullab->getNullabilitySource();
if (!S || S->getBeginLoc().isInvalid()) {
- S = PathDiagnosticLocation::getStmt(N);
+ S = N->getStmtForDiagnostics();
}
if (!S)
@@ -324,8 +323,7 @@ NullabilityChecker::NullabilityBugVisitor::VisitNode(const ExplodedNode *N,
// Generate the extra diagnostic.
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
N->getLocationContext());
- return std::make_shared<PathDiagnosticEventPiece>(Pos, InfoText, true,
- nullptr);
+ return std::make_shared<PathDiagnosticEventPiece>(Pos, InfoText, true);
}
/// Returns true when the value stored at the given location has been
@@ -1203,12 +1201,12 @@ bool ento::shouldRegisterNullabilityBase(const LangOptions &LO) {
void ento::register##name##Checker(CheckerManager &mgr) { \
NullabilityChecker *checker = mgr.getChecker<NullabilityChecker>(); \
checker->Filter.Check##name = true; \
- checker->Filter.CheckName##name = mgr.getCurrentCheckName(); \
+ checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \
checker->NeedTracking = checker->NeedTracking || trackingRequired; \
checker->NoDiagnoseCallsToSystemHeaders = \
checker->NoDiagnoseCallsToSystemHeaders || \
mgr.getAnalyzerOptions().getCheckerBooleanOption( \
- checker, "NoDiagnoseCallsToSystemHeaders", true); \
+ checker, "NoDiagnoseCallsToSystemHeaders", true); \
} \
\
bool ento::shouldRegister##name##Checker(const LangOptions &LO) { \
diff --git a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
index bd8cfb14680f..0e25817c8793 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
@@ -46,8 +46,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
if (!BT_undef)
BT_undef.reset(new BuiltinBug(this, "Uninitialized value used as mutex "
"for @synchronized"));
- auto report =
- llvm::make_unique<BugReport>(*BT_undef, BT_undef->getDescription(), N);
+ auto report = std::make_unique<PathSensitiveBugReport>(
+ *BT_undef, BT_undef->getDescription(), N);
bugreporter::trackExpressionValue(N, Ex, *report);
C.emitReport(std::move(report));
}
@@ -70,8 +70,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
BT_null.reset(new BuiltinBug(
this, "Nil value used as mutex for @synchronized() "
"(no synchronization will occur)"));
- auto report =
- llvm::make_unique<BugReport>(*BT_null, BT_null->getDescription(), N);
+ auto report = std::make_unique<PathSensitiveBugReport>(
+ *BT_null, BT_null->getDescription(), N);
bugreporter::trackExpressionValue(N, Ex, *report);
C.emitReport(std::move(report));
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
index f69a3944a56c..8abb926d4862 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
@@ -144,10 +144,11 @@ void ObjCContainersChecker::checkPreStmt(const CallExpr *CE,
if (!N)
return;
initBugType();
- auto R = llvm::make_unique<BugReport>(*BT, "Index is out of bounds", N);
+ auto R = std::make_unique<PathSensitiveBugReport>(
+ *BT, "Index is out of bounds", N);
R->addRange(IdxExpr->getSourceRange());
- bugreporter::trackExpressionValue(N, IdxExpr, *R,
- /*EnableNullFPSuppression=*/false);
+ bugreporter::trackExpressionValue(
+ N, IdxExpr, *R, bugreporter::TrackingKind::Thorough, false);
C.emitReport(std::move(R));
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
index 33e4d2af000d..1870c08432de 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
@@ -13,12 +13,12 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/SmallSet.h"
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index 767b7bf4063c..344285750f0e 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -159,7 +159,7 @@ void ObjCSelfInitChecker::checkForInvalidSelf(const Expr *E, CheckerContext &C,
if (!BT)
BT.reset(new BugType(this, "Missing \"self = [(super or self) init...]\"",
categories::CoreFoundationObjectiveC));
- C.emitReport(llvm::make_unique<BugReport>(*BT, errorStr, N));
+ C.emitReport(std::make_unique<PathSensitiveBugReport>(*BT, errorStr, N));
}
void ObjCSelfInitChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp
index f435f00c08e7..0575be845374 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp
@@ -67,12 +67,11 @@ class SuperDeallocBRVisitor final : public BugReporterVisitor {
public:
SuperDeallocBRVisitor(SymbolRef ReceiverSymbol)
- : ReceiverSymbol(ReceiverSymbol),
- Satisfied(false) {}
+ : ReceiverSymbol(ReceiverSymbol), Satisfied(false) {}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
void Profile(llvm::FoldingSetNodeID &ID) const override {
ID.Add(ReceiverSymbol);
@@ -188,10 +187,10 @@ void ObjCSuperDeallocChecker::reportUseAfterDealloc(SymbolRef Sym,
Desc = "Use of 'self' after it has been deallocated";
// Generate the report.
- std::unique_ptr<BugReport> BR(
- new BugReport(*DoubleSuperDeallocBugType, Desc, ErrNode));
+ auto BR = std::make_unique<PathSensitiveBugReport>(*DoubleSuperDeallocBugType,
+ Desc, ErrNode);
BR->addRange(S->getSourceRange());
- BR->addVisitor(llvm::make_unique<SuperDeallocBRVisitor>(Sym));
+ BR->addVisitor(std::make_unique<SuperDeallocBRVisitor>(Sym));
C.emitReport(std::move(BR));
}
@@ -243,9 +242,10 @@ ObjCSuperDeallocChecker::isSuperDeallocMessage(const ObjCMethodCall &M) const {
return M.getSelector() == SELdealloc;
}
-std::shared_ptr<PathDiagnosticPiece>
+PathDiagnosticPieceRef
SuperDeallocBRVisitor::VisitNode(const ExplodedNode *Succ,
- BugReporterContext &BRC, BugReport &) {
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &) {
if (Satisfied)
return nullptr;
diff --git a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
index 4b39a97c7e8d..cb4770451572 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
@@ -20,7 +21,6 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
using namespace clang;
@@ -94,7 +94,7 @@ static void Scan(IvarUsageMap& M, const ObjCContainerDecl *D) {
}
static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID,
- SourceManager &SM) {
+ const SourceManager &SM) {
for (const auto *I : C->decls())
if (const auto *FD = dyn_cast<FunctionDecl>(I)) {
SourceLocation L = FD->getBeginLoc();
@@ -148,7 +148,7 @@ static void checkObjCUnusedIvar(const ObjCImplementationDecl *D,
// FIXME: In the future hopefully we can just use the lexical DeclContext
// to go from the ObjCImplementationDecl to the lexically "nested"
// C functions.
- SourceManager &SM = BR.getSourceManager();
+ const SourceManager &SM = BR.getSourceManager();
Scan(M, D->getDeclContext(), SM.getFileID(D->getLocation()), SM);
// Find ivars that are unused.
diff --git a/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp b/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp
index 0aa410de15ff..4a3c2b8cd40e 100644
--- a/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp
@@ -306,7 +306,7 @@ public:
const SmallVector<const FieldDecl *, 20> &OptimalFieldsOrder) const {
if (!PaddingBug)
PaddingBug =
- llvm::make_unique<BugType>(this, "Excessive Padding", "Performance");
+ std::make_unique<BugType>(this, "Excessive Padding", "Performance");
SmallString<100> Buf;
llvm::raw_svector_ostream Os(Buf);
@@ -335,7 +335,8 @@ public:
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::create(RD, BR->getSourceManager());
- auto Report = llvm::make_unique<BugReport>(*PaddingBug, Os.str(), CELoc);
+ auto Report =
+ std::make_unique<BasicBugReport>(*PaddingBug, Os.str(), CELoc);
Report->setDeclWithIssue(RD);
Report->addRange(RD->getSourceRange());
BR->emitReport(std::move(Report));
diff --git a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
index 03c3f4dd2357..259f23abdc95 100644
--- a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
@@ -119,12 +119,12 @@ const MemRegion *PointerArithChecker::getArrayRegion(const MemRegion *Region,
AllocKind &AKind,
CheckerContext &C) const {
assert(Region);
- while (Region->getKind() == MemRegion::Kind::CXXBaseObjectRegionKind) {
- Region = Region->getAs<CXXBaseObjectRegion>()->getSuperRegion();
+ while (const auto *BaseRegion = dyn_cast<CXXBaseObjectRegion>(Region)) {
+ Region = BaseRegion->getSuperRegion();
Polymorphic = true;
}
- if (Region->getKind() == MemRegion::Kind::ElementRegionKind) {
- Region = Region->getAs<ElementRegion>()->getSuperRegion();
+ if (const auto *ElemRegion = dyn_cast<ElementRegion>(Region)) {
+ Region = ElemRegion->getSuperRegion();
}
ProgramStateRef State = C.getState();
@@ -137,7 +137,7 @@ const MemRegion *PointerArithChecker::getArrayRegion(const MemRegion *Region,
}
// When the region is symbolic and we do not have any information about it,
// assume that this is an array to avoid false positives.
- if (Region->getKind() == MemRegion::Kind::SymbolicRegionKind)
+ if (isa<SymbolicRegion>(Region))
return Region;
// No AllocKind stored and not symbolic, assume that it points to a single
@@ -173,8 +173,8 @@ void PointerArithChecker::reportPointerArithMisuse(const Expr *E,
this, "Dangerous pointer arithmetic",
"Pointer arithmetic on a pointer to base class is dangerous "
"because derived and base class may have different size."));
- auto R = llvm::make_unique<BugReport>(*BT_polyArray,
- BT_polyArray->getDescription(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(
+ *BT_polyArray, BT_polyArray->getDescription(), N);
R->addRange(E->getSourceRange());
R->markInteresting(ArrayRegion);
C.emitReport(std::move(R));
@@ -196,8 +196,8 @@ void PointerArithChecker::reportPointerArithMisuse(const Expr *E,
"Pointer arithmetic on non-array "
"variables relies on memory layout, "
"which is dangerous."));
- auto R = llvm::make_unique<BugReport>(*BT_pointerArith,
- BT_pointerArith->getDescription(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(
+ *BT_pointerArith, BT_pointerArith->getDescription(), N);
R->addRange(SR);
R->markInteresting(Region);
C.emitReport(std::move(R));
diff --git a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index c9512f4fc42f..88d0eb2ae748 100644
--- a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -63,7 +63,8 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
new BuiltinBug(this, "Pointer subtraction",
"Subtraction of two pointers that do not point to "
"the same memory chunk may cause incorrect result."));
- auto R = llvm::make_unique<BugReport>(*BT, BT->getDescription(), N);
+ auto R =
+ std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
R->addRange(B->getSourceRange());
C.emitReport(std::move(R));
}
diff --git a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index 33f677e1c258..8649b8b96dd0 100644
--- a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -240,7 +240,7 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
- auto report = llvm::make_unique<BugReport>(
+ auto report = std::make_unique<PathSensitiveBugReport>(
*BT_doublelock, "This lock has already been acquired", N);
report->addRange(CE->getArg(0)->getSourceRange());
C.emitReport(std::move(report));
@@ -305,7 +305,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
- auto Report = llvm::make_unique<BugReport>(
+ auto Report = std::make_unique<PathSensitiveBugReport>(
*BT_doubleunlock, "This lock has already been unlocked", N);
Report->addRange(CE->getArg(0)->getSourceRange());
C.emitReport(std::move(Report));
@@ -328,7 +328,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
- auto report = llvm::make_unique<BugReport>(
+ auto report = std::make_unique<PathSensitiveBugReport>(
*BT_lor, "This was not the most recently acquired lock. Possible "
"lock order reversal", N);
report->addRange(CE->getArg(0)->getSourceRange());
@@ -399,7 +399,8 @@ void PthreadLockChecker::DestroyLock(CheckerContext &C, const CallExpr *CE,
ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
- auto Report = llvm::make_unique<BugReport>(*BT_destroylock, Message, N);
+ auto Report =
+ std::make_unique<PathSensitiveBugReport>(*BT_destroylock, Message, N);
Report->addRange(CE->getArg(0)->getSourceRange());
C.emitReport(std::move(Report));
}
@@ -438,7 +439,8 @@ void PthreadLockChecker::InitLock(CheckerContext &C, const CallExpr *CE,
ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
- auto Report = llvm::make_unique<BugReport>(*BT_initlock, Message, N);
+ auto Report =
+ std::make_unique<PathSensitiveBugReport>(*BT_initlock, Message, N);
Report->addRange(CE->getArg(0)->getSourceRange());
C.emitReport(std::move(Report));
}
@@ -451,7 +453,7 @@ void PthreadLockChecker::reportUseDestroyedBug(CheckerContext &C,
ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
- auto Report = llvm::make_unique<BugReport>(
+ auto Report = std::make_unique<PathSensitiveBugReport>(
*BT_destroylock, "This lock has already been destroyed", N);
Report->addRange(CE->getArg(0)->getSourceRange());
C.emitReport(std::move(Report));
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index 4a3a8dae23a7..6f8cb1432bb1 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -875,7 +875,7 @@ void RetainCountChecker::processNonLeakError(ProgramStateRef St,
if (!N)
return;
- auto report = llvm::make_unique<RefCountReport>(
+ auto report = std::make_unique<RefCountReport>(
errorKindToBugKind(ErrorKind, Sym),
C.getASTContext().getLangOpts(), N, Sym);
report->addRange(ErrorRange);
@@ -1095,7 +1095,7 @@ ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
if (N) {
const LangOptions &LOpts = C.getASTContext().getLangOpts();
auto R =
- llvm::make_unique<RefLeakReport>(leakAtReturn, LOpts, N, Sym, C);
+ std::make_unique<RefLeakReport>(leakAtReturn, LOpts, N, Sym, C);
C.emitReport(std::move(R));
}
return N;
@@ -1119,7 +1119,7 @@ ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S,
ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag);
if (N) {
- auto R = llvm::make_unique<RefCountReport>(
+ auto R = std::make_unique<RefCountReport>(
returnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym);
C.emitReport(std::move(R));
}
@@ -1273,7 +1273,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
os << "has a +" << V.getCount() << " retain count";
const LangOptions &LOpts = Ctx.getASTContext().getLangOpts();
- auto R = llvm::make_unique<RefCountReport>(overAutorelease, LOpts, N, Sym,
+ auto R = std::make_unique<RefCountReport>(overAutorelease, LOpts, N, Sym,
os.str());
Ctx.emitReport(std::move(R));
}
@@ -1321,7 +1321,7 @@ RetainCountChecker::processLeaks(ProgramStateRef state,
if (N) {
for (SymbolRef L : Leaked) {
const RefCountBug &BT = Pred ? leakWithinFunction : leakAtReturn;
- Ctx.emitReport(llvm::make_unique<RefLeakReport>(BT, LOpts, N, L, Ctx));
+ Ctx.emitReport(std::make_unique<RefLeakReport>(BT, LOpts, N, L, Ctx));
}
}
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
index 124c0e5040b9..dd79bbef321c 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
@@ -21,12 +21,12 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ParentMap.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/RetainSummaryManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Analysis/SelectorExtras.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 796fd882ffd5..9853758f7f2c 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -325,22 +325,22 @@ public:
ID.AddPointer(Sym);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
- std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
- const ExplodedNode *N,
- BugReport &BR) override;
+ PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ PathSensitiveBugReport &BR) override;
};
class RefLeakReportVisitor : public RefCountReportVisitor {
public:
RefLeakReportVisitor(SymbolRef sym) : RefCountReportVisitor(sym) {}
- std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
- const ExplodedNode *N,
- BugReport &BR) override;
+ PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ PathSensitiveBugReport &BR) override;
};
} // end namespace retaincountchecker
@@ -448,9 +448,9 @@ annotateStartParameter(const ExplodedNode *N, SymbolRef Sym,
return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
}
-std::shared_ptr<PathDiagnosticPiece>
-RefCountReportVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC, BugReport &BR) {
+PathDiagnosticPieceRef
+RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
const auto &BT = static_cast<const RefCountBug&>(BR.getBugType());
const auto *Checker =
@@ -709,21 +709,22 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
LeakContext)
FirstBinding = nullptr;
- return AllocationInfo(AllocationNodeInCurrentOrParentContext,
- FirstBinding,
+ return AllocationInfo(AllocationNodeInCurrentOrParentContext, FirstBinding,
InterestingMethodContext);
}
-std::shared_ptr<PathDiagnosticPiece>
+PathDiagnosticPieceRef
RefCountReportVisitor::getEndPath(BugReporterContext &BRC,
- const ExplodedNode *EndN, BugReport &BR) {
+ const ExplodedNode *EndN,
+ PathSensitiveBugReport &BR) {
BR.markInteresting(Sym);
return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR);
}
-std::shared_ptr<PathDiagnosticPiece>
+PathDiagnosticPieceRef
RefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
- const ExplodedNode *EndN, BugReport &BR) {
+ const ExplodedNode *EndN,
+ PathSensitiveBugReport &BR) {
// Tell the BugReporterContext to report cases when the tracked symbol is
// assigned to different variables, etc.
@@ -737,13 +738,7 @@ RefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
const MemRegion* FirstBinding = AllocI.R;
BR.markInteresting(AllocI.InterestingMethodContext);
- SourceManager& SM = BRC.getSourceManager();
-
- // Compute an actual location for the leak. Sometimes a leak doesn't
- // occur at an actual statement (e.g., transition between blocks; end
- // of function) so we need to walk the graph and compute a real location.
- const ExplodedNode *LeakN = EndN;
- PathDiagnosticLocation L = PathDiagnosticLocation::createEndOfPath(LeakN, SM);
+ PathDiagnosticLocation L = cast<RefLeakReport>(BR).getEndOfPath();
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
@@ -814,19 +809,19 @@ RefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
}
RefCountReport::RefCountReport(const RefCountBug &D, const LangOptions &LOpts,
- ExplodedNode *n, SymbolRef sym,
- bool isLeak)
- : BugReport(D, D.getDescription(), n), Sym(sym), isLeak(isLeak) {
+ ExplodedNode *n, SymbolRef sym, bool isLeak)
+ : PathSensitiveBugReport(D, D.getDescription(), n), Sym(sym),
+ isLeak(isLeak) {
if (!isLeak)
- addVisitor(llvm::make_unique<RefCountReportVisitor>(sym));
+ addVisitor(std::make_unique<RefCountReportVisitor>(sym));
}
RefCountReport::RefCountReport(const RefCountBug &D, const LangOptions &LOpts,
ExplodedNode *n, SymbolRef sym,
StringRef endText)
- : BugReport(D, D.getDescription(), endText, n) {
+ : PathSensitiveBugReport(D, D.getDescription(), endText, n) {
- addVisitor(llvm::make_unique<RefCountReportVisitor>(sym));
+ addVisitor(std::make_unique<RefCountReportVisitor>(sym));
}
void RefLeakReport::deriveParamLocation(CheckerContext &Ctx, SymbolRef sym) {
@@ -873,7 +868,7 @@ void RefLeakReport::deriveAllocLocation(CheckerContext &Ctx,
// FIXME: This will crash the analyzer if an allocation comes from an
// implicit call (ex: a destructor call).
// (Currently there are no such allocations in Cocoa, though.)
- AllocStmt = PathDiagnosticLocation::getStmt(AllocNode);
+ AllocStmt = AllocNode->getStmtForDiagnostics();
if (!AllocStmt) {
AllocBinding = nullptr;
@@ -918,5 +913,5 @@ RefLeakReport::RefLeakReport(const RefCountBug &D, const LangOptions &LOpts,
createDescription(Ctx);
- addVisitor(llvm::make_unique<RefLeakReportVisitor>(sym));
+ addVisitor(std::make_unique<RefLeakReportVisitor>(sym));
}
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h
index ef3c75f87af5..e9e277754054 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h
@@ -14,10 +14,10 @@
#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_DIAGNOSTICS_H
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_DIAGNOSTICS_H
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/RetainSummaryManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
namespace clang {
@@ -53,7 +53,7 @@ private:
static StringRef bugTypeToName(RefCountBugType BT);
};
-class RefCountReport : public BugReport {
+class RefCountReport : public PathSensitiveBugReport {
protected:
SymbolRef Sym;
bool isLeak = false;
@@ -67,16 +67,17 @@ public:
ExplodedNode *n, SymbolRef sym,
StringRef endText);
- llvm::iterator_range<ranges_iterator> getRanges() override {
+ ArrayRef<SourceRange> getRanges() const override {
if (!isLeak)
- return BugReport::getRanges();
- return llvm::make_range(ranges_iterator(), ranges_iterator());
+ return PathSensitiveBugReport::getRanges();
+ return {};
}
};
class RefLeakReport : public RefCountReport {
const MemRegion* AllocBinding;
const Stmt *AllocStmt;
+ PathDiagnosticLocation Location;
// Finds the function declaration where a leak warning for the parameter
// 'sym' should be raised.
@@ -89,11 +90,14 @@ class RefLeakReport : public RefCountReport {
public:
RefLeakReport(const RefCountBug &D, const LangOptions &LOpts, ExplodedNode *n,
SymbolRef sym, CheckerContext &Ctx);
-
- PathDiagnosticLocation getLocation(const SourceManager &SM) const override {
+ PathDiagnosticLocation getLocation() const override {
assert(Location.isValid());
return Location;
}
+
+ PathDiagnosticLocation getEndOfPath() const {
+ return PathSensitiveBugReport::getLocation();
+ }
};
} // end namespace retaincountchecker
diff --git a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index 9eb47e0526dc..abd1a074b487 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
@@ -79,7 +79,8 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
// reference is outside the range.
// Generate a report for this bug.
- auto report = llvm::make_unique<BugReport>(*BT, BT->getDescription(), N);
+ auto report =
+ std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
report->addRange(RetE->getSourceRange());
C.emitReport(std::move(report));
diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
index f55c369da67e..fbd15d864424 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
@@ -83,7 +83,8 @@ static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE,
if (!N)
return;
- auto Report = llvm::make_unique<BugReport>(BT, BT.getDescription(), N);
+ auto Report =
+ std::make_unique<PathSensitiveBugReport>(BT, BT.getDescription(), N);
Report->addRange(RetE->getSourceRange());
bugreporter::trackExpressionValue(N, TrackingE ? TrackingE : RetE, *Report);
diff --git a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
index ec5e9622c236..8193bcbef4cd 100644
--- a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
@@ -206,8 +206,8 @@ void SimpleStreamChecker::reportDoubleClose(SymbolRef FileDescSym,
return;
// Generate the report.
- auto R = llvm::make_unique<BugReport>(*DoubleCloseBugType,
- "Closing a previously closed file stream", ErrNode);
+ auto R = std::make_unique<PathSensitiveBugReport>(
+ *DoubleCloseBugType, "Closing a previously closed file stream", ErrNode);
R->addRange(Call.getSourceRange());
R->markInteresting(FileDescSym);
C.emitReport(std::move(R));
@@ -219,8 +219,9 @@ void SimpleStreamChecker::reportLeaks(ArrayRef<SymbolRef> LeakedStreams,
// Attach bug reports to the leak node.
// TODO: Identify the leaked file descriptor.
for (SymbolRef LeakedStream : LeakedStreams) {
- auto R = llvm::make_unique<BugReport>(*LeakBugType,
- "Opened file is never closed; potential resource leak", ErrNode);
+ auto R = std::make_unique<PathSensitiveBugReport>(
+ *LeakBugType, "Opened file is never closed; potential resource leak",
+ ErrNode);
R->markInteresting(LeakedStream);
C.emitReport(std::move(R));
}
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index b93bed5c3097..7285d27495a7 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -155,14 +155,15 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C,
if (!N)
return;
if (!BT_returnstack)
- BT_returnstack = llvm::make_unique<BuiltinBug>(
+ BT_returnstack = std::make_unique<BuiltinBug>(
this, "Return of address to stack-allocated memory");
// Generate a report for this bug.
SmallString<128> buf;
llvm::raw_svector_ostream os(buf);
SourceRange range = genName(os, R, C.getASTContext());
os << " returned to caller";
- auto report = llvm::make_unique<BugReport>(*BT_returnstack, os.str(), N);
+ auto report =
+ std::make_unique<PathSensitiveBugReport>(*BT_returnstack, os.str(), N);
report->addRange(RetE->getSourceRange());
if (range.isValid())
report->addRange(range);
@@ -193,14 +194,14 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
if (!N)
continue;
if (!BT_capturedstackasync)
- BT_capturedstackasync = llvm::make_unique<BuiltinBug>(
+ BT_capturedstackasync = std::make_unique<BuiltinBug>(
this, "Address of stack-allocated memory is captured");
SmallString<128> Buf;
llvm::raw_svector_ostream Out(Buf);
SourceRange Range = genName(Out, Region, C.getASTContext());
Out << " is captured by an asynchronously-executed block";
- auto Report =
- llvm::make_unique<BugReport>(*BT_capturedstackasync, Out.str(), N);
+ auto Report = std::make_unique<PathSensitiveBugReport>(
+ *BT_capturedstackasync, Out.str(), N);
if (Range.isValid())
Report->addRange(Range);
C.emitReport(std::move(Report));
@@ -216,14 +217,14 @@ void StackAddrEscapeChecker::checkReturnedBlockCaptures(
if (!N)
continue;
if (!BT_capturedstackret)
- BT_capturedstackret = llvm::make_unique<BuiltinBug>(
+ BT_capturedstackret = std::make_unique<BuiltinBug>(
this, "Address of stack-allocated memory is captured");
SmallString<128> Buf;
llvm::raw_svector_ostream Out(Buf);
SourceRange Range = genName(Out, Region, C.getASTContext());
Out << " is captured by a returned block";
- auto Report =
- llvm::make_unique<BugReport>(*BT_capturedstackret, Out.str(), N);
+ auto Report = std::make_unique<PathSensitiveBugReport>(*BT_capturedstackret,
+ Out.str(), N);
if (Range.isValid())
Report->addRange(Range);
C.emitReport(std::move(Report));
@@ -331,7 +332,7 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
return;
if (!BT_stackleak)
- BT_stackleak = llvm::make_unique<BuiltinBug>(
+ BT_stackleak = std::make_unique<BuiltinBug>(
this, "Stack address stored into global variable",
"Stack address was saved into a global variable. "
"This is dangerous because the address will become "
@@ -351,7 +352,8 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
const VarRegion *VR = cast<VarRegion>(P.first->getBaseRegion());
Out << *VR->getDecl()
<< "' upon returning to the caller. This will be a dangling reference";
- auto Report = llvm::make_unique<BugReport>(*BT_stackleak, Out.str(), N);
+ auto Report =
+ std::make_unique<PathSensitiveBugReport>(*BT_stackleak, Out.str(), N);
if (Range.isValid())
Report->addRange(Range);
diff --git a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 1ea5e0769513..c254408351c8 100644
--- a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -277,7 +277,7 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
new BuiltinBug(this, "Illegal whence argument",
"The whence argument to fseek() should be "
"SEEK_SET, SEEK_END, or SEEK_CUR."));
- C.emitReport(llvm::make_unique<BugReport>(
+ C.emitReport(std::make_unique<PathSensitiveBugReport>(
*BT_illegalwhence, BT_illegalwhence->getDescription(), N));
}
}
@@ -345,7 +345,7 @@ ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state,
if (!BT_nullfp)
BT_nullfp.reset(new BuiltinBug(this, "NULL stream pointer",
"Stream pointer might be NULL."));
- C.emitReport(llvm::make_unique<BugReport>(
+ C.emitReport(std::make_unique<PathSensitiveBugReport>(
*BT_nullfp, BT_nullfp->getDescription(), N));
}
return nullptr;
@@ -375,7 +375,7 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE,
BT_doubleclose.reset(new BuiltinBug(
this, "Double fclose", "Try to close a file Descriptor already"
" closed. Cause undefined behaviour."));
- C.emitReport(llvm::make_unique<BugReport>(
+ C.emitReport(std::make_unique<PathSensitiveBugReport>(
*BT_doubleclose, BT_doubleclose->getDescription(), N));
}
return nullptr;
@@ -405,7 +405,7 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
BT_ResourceLeak.reset(
new BuiltinBug(this, "Resource Leak",
"Opened File never closed. Potential Resource leak."));
- C.emitReport(llvm::make_unique<BugReport>(
+ C.emitReport(std::make_unique<PathSensitiveBugReport>(
*BT_ResourceLeak, BT_ResourceLeak->getDescription(), N));
}
}
diff --git a/lib/StaticAnalyzer/Checkers/Taint.cpp b/lib/StaticAnalyzer/Checkers/Taint.cpp
index bc120949ee4f..574d4ed1e600 100644
--- a/lib/StaticAnalyzer/Checkers/Taint.cpp
+++ b/lib/StaticAnalyzer/Checkers/Taint.cpp
@@ -204,16 +204,16 @@ bool taint::isTainted(ProgramStateRef State, SymbolRef Sym, TaintTagType Kind) {
return false;
}
-std::shared_ptr<PathDiagnosticPiece>
-TaintBugVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
- BugReport &BR) {
+PathDiagnosticPieceRef TaintBugVisitor::VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
// Find the ExplodedNode where the taint was first introduced
if (!isTainted(N->getState(), V) ||
isTainted(N->getFirstPred()->getState(), V))
return nullptr;
- const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ const Stmt *S = N->getStmtForDiagnostics();
if (!S)
return nullptr;
diff --git a/lib/StaticAnalyzer/Checkers/Taint.h b/lib/StaticAnalyzer/Checkers/Taint.h
index 72cf6a79d52c..8940916c1933 100644
--- a/lib/StaticAnalyzer/Checkers/Taint.h
+++ b/lib/StaticAnalyzer/Checkers/Taint.h
@@ -89,9 +89,9 @@ public:
TaintBugVisitor(const SVal V) : V(V) {}
void Profile(llvm::FoldingSetNodeID &ID) const override { ID.Add(V); }
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
};
} // namespace taint
diff --git a/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
index 094762e2faf8..f81705304f3a 100644
--- a/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
@@ -52,7 +52,7 @@ void TaintTesterChecker::checkPostStmt(const Expr *E,
if (isTainted(State, E, C.getLocationContext())) {
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
initBugType();
- auto report = llvm::make_unique<BugReport>(*BT, "tainted",N);
+ auto report = std::make_unique<PathSensitiveBugReport>(*BT, "tainted", N);
report->addRange(E->getSourceRange());
C.emitReport(std::move(report));
}
diff --git a/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
index 7a33845a6a26..3663b0963692 100644
--- a/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
@@ -69,9 +69,9 @@ public:
ID.Add(SFC);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *Succ,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
};
class TestAfterDivZeroChecker
@@ -92,9 +92,9 @@ public:
REGISTER_SET_WITH_PROGRAMSTATE(DivZeroMap, ZeroState)
-std::shared_ptr<PathDiagnosticPiece>
-DivisionBRVisitor::VisitNode(const ExplodedNode *Succ,
- BugReporterContext &BRC, BugReport &BR) {
+PathDiagnosticPieceRef
+DivisionBRVisitor::VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
if (Satisfied)
return nullptr;
@@ -167,12 +167,12 @@ void TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const {
if (!DivZeroBug)
DivZeroBug.reset(new BuiltinBug(this, "Division by zero"));
- auto R = llvm::make_unique<BugReport>(
+ auto R = std::make_unique<PathSensitiveBugReport>(
*DivZeroBug, "Value being compared against zero has already been used "
"for division",
N);
- R->addVisitor(llvm::make_unique<DivisionBRVisitor>(Val.getAsSymbol(),
+ R->addVisitor(std::make_unique<DivisionBRVisitor>(Val.getAsSymbol(),
C.getStackFrame()));
C.emitReport(std::move(R));
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
index 3a4a1dbf641b..247cba7dc933 100644
--- a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
@@ -96,7 +96,8 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
Ex = FindIt.FindExpr(Ex);
// Emit the bug report.
- auto R = llvm::make_unique<BugReport>(*BT, BT->getDescription(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(
+ *BT, BT->getDescription(), N);
bugreporter::trackExpressionValue(N, Ex, *R);
R->addRange(Ex->getSourceRange());
diff --git a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index c787ef58660a..7b581bef3900 100644
--- a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
@@ -83,11 +83,12 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
os << "Variable '" << VD->getName()
<< "' is uninitialized when captured by block";
- auto R = llvm::make_unique<BugReport>(*BT, os.str(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
R->addRange(Ex->getSourceRange());
- R->addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
- *V, VR, /*EnableNullFPSuppression*/ false));
+ R->addVisitor(std::make_unique<FindLastStoreBRVisitor>(
+ *V, VR, /*EnableNullFPSuppression*/ false,
+ bugreporter::TrackingKind::Thorough));
R->disablePathPruning();
// need location of block
C.emitReport(std::move(R));
diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index 1ae287d39f11..a2f3e0da13fb 100644
--- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
@@ -170,7 +170,7 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
<< "' expression is undefined";
}
}
- auto report = llvm::make_unique<BugReport>(*BT, OS.str(), N);
+ auto report = std::make_unique<PathSensitiveBugReport>(*BT, OS.str(), N);
if (Ex) {
report->addRange(Ex->getSourceRange());
bugreporter::trackExpressionValue(N, Ex, *report);
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
index 4c517d6f0562..2f075eaeb03b 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
@@ -52,7 +52,7 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
BT.reset(new BuiltinBug(this, "Array subscript is undefined"));
// Generate a report for this bug.
- auto R = llvm::make_unique<BugReport>(*BT, BT->getName(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
R->addRange(A->getIdx()->getSourceRange());
bugreporter::trackExpressionValue(N, A->getIdx(), *R);
C.emitReport(std::move(R));
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index d32d2a4042de..277a8a143328 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -85,7 +85,7 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
}
if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) {
- const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
+ const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
ex = VD->getInit();
}
@@ -108,7 +108,7 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
if (OS.str().empty())
OS << DefaultMsg;
- auto R = llvm::make_unique<BugReport>(*BT, OS.str(), N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, OS.str(), N);
if (ex) {
R->addRange(ex->getSourceRange());
bugreporter::trackExpressionValue(N, ex, *R);
diff --git a/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp b/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
index 9d608c12d19b..020df8a1bb8c 100644
--- a/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -24,7 +24,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
using namespace clang;
using namespace clang::ento;
@@ -187,7 +187,7 @@ void UninitializedObjectChecker::checkEndFunction(
if (Opts.ShouldConvertNotesToWarnings) {
for (const auto &Pair : UninitFields) {
- auto Report = llvm::make_unique<BugReport>(
+ auto Report = std::make_unique<PathSensitiveBugReport>(
*BT_uninitField, Pair.second, Node, LocUsedForUniqueing,
Node->getLocationContext()->getDecl());
Context.emitReport(std::move(Report));
@@ -201,7 +201,7 @@ void UninitializedObjectChecker::checkEndFunction(
<< (UninitFields.size() == 1 ? "" : "s")
<< " at the end of the constructor call";
- auto Report = llvm::make_unique<BugReport>(
+ auto Report = std::make_unique<PathSensitiveBugReport>(
*BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
Node->getLocationContext()->getDecl());
diff --git a/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp b/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
index a5dc250104f3..f0dd0bf813af 100644
--- a/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ b/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -18,7 +18,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
using namespace clang;
using namespace clang::ento;
@@ -260,12 +260,13 @@ static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
break;
}
- while (R->getAs<CXXBaseObjectRegion>()) {
+ while (isa<CXXBaseObjectRegion>(R)) {
NeedsCastBack = true;
-
- if (!isa<TypedValueRegion>(R->getSuperRegion()))
+ const auto *SuperR = dyn_cast<TypedValueRegion>(R->getSuperRegion());
+ if (!SuperR)
break;
- R = R->getSuperRegion()->getAs<TypedValueRegion>();
+
+ R = SuperR;
}
return DereferenceInfo{R, NeedsCastBack, /*IsCyclic*/ false};
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 2ccb519891f3..f4e225d836f3 100644
--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -135,7 +135,7 @@ void UnixAPIMisuseChecker::ReportOpenBug(CheckerContext &C,
LazyInitialize(this, BT_open, "Improper use of 'open'");
- auto Report = llvm::make_unique<BugReport>(*BT_open, Msg, N);
+ auto Report = std::make_unique<PathSensitiveBugReport>(*BT_open, Msg, N);
Report->addRange(SR);
C.emitReport(std::move(Report));
}
@@ -304,7 +304,8 @@ void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
LazyInitialize(this, BT_pthreadOnce, "Improper use of 'pthread_once'");
- auto report = llvm::make_unique<BugReport>(*BT_pthreadOnce, os.str(), N);
+ auto report =
+ std::make_unique<PathSensitiveBugReport>(*BT_pthreadOnce, os.str(), N);
report->addRange(CE->getArg(0)->getSourceRange());
C.emitReport(std::move(report));
}
@@ -347,7 +348,8 @@ bool UnixAPIPortabilityChecker::ReportZeroByteAllocation(
SmallString<256> S;
llvm::raw_svector_ostream os(S);
os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";
- auto report = llvm::make_unique<BugReport>(*BT_mallocZero, os.str(), N);
+ auto report =
+ std::make_unique<PathSensitiveBugReport>(*BT_mallocZero, os.str(), N);
report->addRange(arg->getSourceRange());
bugreporter::trackExpressionValue(N, arg, *report);
diff --git a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index 0b0bf8465c9d..65dd82675df9 100644
--- a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
@@ -55,7 +55,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
const Decl *D = nullptr;
CFG *C = nullptr;
- ParentMap *PM = nullptr;
+ const ParentMap *PM = nullptr;
const LocationContext *LC = nullptr;
// Iterate over ExplodedGraph
for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end();
diff --git a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index 1630896c3b60..b92757312dc6 100644
--- a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -72,7 +72,7 @@ void VLASizeChecker::reportBug(
break;
}
- auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
+ auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
report->addVisitor(std::move(Visitor));
report->addRange(SizeE->getSourceRange());
bugreporter::trackExpressionValue(N, SizeE, *report);
@@ -110,7 +110,7 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
// Check if the size is tainted.
if (isTainted(state, sizeV)) {
reportBug(VLA_Tainted, SE, nullptr, C,
- llvm::make_unique<TaintBugVisitor>(sizeV));
+ std::make_unique<TaintBugVisitor>(sizeV));
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/ValistChecker.cpp b/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
index 13ad3d98e8eb..a3610514a924 100644
--- a/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
@@ -46,7 +46,7 @@ public:
};
DefaultBool ChecksEnabled[CK_NumCheckKinds];
- CheckName CheckNames[CK_NumCheckKinds];
+ CheckerNameRef CheckNames[CK_NumCheckKinds];
void checkPreStmt(const VAArgExpr *VAA, CheckerContext &C) const;
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
@@ -77,20 +77,20 @@ private:
ID.AddPointer(&X);
ID.AddPointer(Reg);
}
- std::shared_ptr<PathDiagnosticPiece>
- getEndPath(BugReporterContext &BRC, const ExplodedNode *EndPathNode,
- BugReport &BR) override {
+ PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *EndPathNode,
+ PathSensitiveBugReport &BR) override {
if (!IsLeak)
return nullptr;
- PathDiagnosticLocation L = PathDiagnosticLocation::createEndOfPath(
- EndPathNode, BRC.getSourceManager());
+ PathDiagnosticLocation L = BR.getLocation();
// Do not add the statement itself as a range in case of leak.
- return std::make_shared<PathDiagnosticEventPiece>(L, BR.getDescription(), false);
+ return std::make_shared<PathDiagnosticEventPiece>(L, BR.getDescription(),
+ false);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
private:
const MemRegion *Reg;
@@ -115,7 +115,9 @@ const SmallVector<ValistChecker::VAListAccepter, 15>
// vswprintf is the wide version of vsnprintf,
// vsprintf has no wide version
{{"vswscanf", 3}, 2}};
-const CallDescription ValistChecker::VaStart("__builtin_va_start", 2),
+
+const CallDescription
+ ValistChecker::VaStart("__builtin_va_start", /*Args=*/2, /*Params=*/1),
ValistChecker::VaCopy("__builtin_va_copy", 2),
ValistChecker::VaEnd("__builtin_va_end", 1);
} // end anonymous namespace
@@ -253,9 +255,9 @@ void ValistChecker::reportUninitializedAccess(const MemRegion *VAList,
BT_uninitaccess.reset(new BugType(CheckNames[CK_Uninitialized],
"Uninitialized va_list",
categories::MemoryError));
- auto R = llvm::make_unique<BugReport>(*BT_uninitaccess, Msg, N);
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT_uninitaccess, Msg, N);
R->markInteresting(VAList);
- R->addVisitor(llvm::make_unique<ValistBugVisitor>(VAList));
+ R->addVisitor(std::make_unique<ValistBugVisitor>(VAList));
C.emitReport(std::move(R));
}
}
@@ -282,7 +284,7 @@ void ValistChecker::reportLeakedVALists(const RegionVector &LeakedVALists,
const ExplodedNode *StartNode = getStartCallSite(N, Reg);
PathDiagnosticLocation LocUsedForUniqueing;
- if (const Stmt *StartCallStmt = PathDiagnosticLocation::getStmt(StartNode))
+ if (const Stmt *StartCallStmt = StartNode->getStmtForDiagnostics())
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
StartCallStmt, C.getSourceManager(), StartNode->getLocationContext());
@@ -294,11 +296,11 @@ void ValistChecker::reportLeakedVALists(const RegionVector &LeakedVALists,
OS << " " << VariableName;
OS << Msg2;
- auto R = llvm::make_unique<BugReport>(
+ auto R = std::make_unique<PathSensitiveBugReport>(
*BT_leakedvalist, OS.str(), N, LocUsedForUniqueing,
StartNode->getLocationContext()->getDecl());
R->markInteresting(Reg);
- R->addVisitor(llvm::make_unique<ValistBugVisitor>(Reg, true));
+ R->addVisitor(std::make_unique<ValistBugVisitor>(Reg, true));
C.emitReport(std::move(R));
}
}
@@ -373,13 +375,12 @@ void ValistChecker::checkVAListEndCall(const CallEvent &Call,
C.addTransition(State);
}
-std::shared_ptr<PathDiagnosticPiece> ValistChecker::ValistBugVisitor::VisitNode(
- const ExplodedNode *N, BugReporterContext &BRC,
- BugReport &) {
+PathDiagnosticPieceRef ValistChecker::ValistBugVisitor::VisitNode(
+ const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &) {
ProgramStateRef State = N->getState();
ProgramStateRef StatePrev = N->getFirstPred()->getState();
- const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ const Stmt *S = N->getStmtForDiagnostics();
if (!S)
return nullptr;
@@ -411,7 +412,8 @@ bool ento::shouldRegisterValistBase(const LangOptions &LO) {
void ento::register##name##Checker(CheckerManager &mgr) { \
ValistChecker *checker = mgr.getChecker<ValistChecker>(); \
checker->ChecksEnabled[ValistChecker::CK_##name] = true; \
- checker->CheckNames[ValistChecker::CK_##name] = mgr.getCurrentCheckName(); \
+ checker->CheckNames[ValistChecker::CK_##name] = \
+ mgr.getCurrentCheckerName(); \
} \
\
bool ento::shouldRegister##name##Checker(const LangOptions &LO) { \
diff --git a/lib/StaticAnalyzer/Checkers/VforkChecker.cpp b/lib/StaticAnalyzer/Checkers/VforkChecker.cpp
index 40d14aa5c7d4..6724eead5072 100644
--- a/lib/StaticAnalyzer/Checkers/VforkChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VforkChecker.cpp
@@ -132,7 +132,7 @@ void VforkChecker::reportBug(const char *What, CheckerContext &C,
if (Details)
os << "; " << Details;
- auto Report = llvm::make_unique<BugReport>(*BT, os.str(), N);
+ auto Report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
// TODO: mark vfork call in BugReportVisitor
C.emitReport(std::move(Report));
}
diff --git a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
index 762c9c1c8d7a..12cee5f8d4f7 100644
--- a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines a checker that checks virtual function calls during
+// This file defines a checker that checks virtual method calls during
// construction or destruction of C++ objects.
//
//===----------------------------------------------------------------------===//
@@ -40,11 +40,10 @@ template <> struct FoldingSetTrait<ObjectState> {
namespace {
class VirtualCallChecker
: public Checker<check::BeginFunction, check::EndFunction, check::PreCall> {
- mutable std::unique_ptr<BugType> BT;
-
public:
- // The flag to determine if pure virtual functions should be issued only.
- DefaultBool IsPureOnly;
+ // These are going to be null if the respective check is disabled.
+ mutable std::unique_ptr<BugType> BT_Pure, BT_Impure;
+ bool ShowFixIts = false;
void checkBeginFunction(CheckerContext &C) const;
void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
@@ -53,87 +52,13 @@ public:
private:
void registerCtorDtorCallInState(bool IsBeginFunction,
CheckerContext &C) const;
- void reportBug(StringRef Msg, bool PureError, const MemRegion *Reg,
- CheckerContext &C) const;
-
- class VirtualBugVisitor : public BugReporterVisitor {
- private:
- const MemRegion *ObjectRegion;
- bool Found;
-
- public:
- VirtualBugVisitor(const MemRegion *R) : ObjectRegion(R), Found(false) {}
-
- void Profile(llvm::FoldingSetNodeID &ID) const override {
- static int X = 0;
- ID.AddPointer(&X);
- ID.AddPointer(ObjectRegion);
- }
-
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
- };
};
} // end namespace
// GDM (generic data map) to the memregion of this for the ctor and dtor.
REGISTER_MAP_WITH_PROGRAMSTATE(CtorDtorMap, const MemRegion *, ObjectState)
-std::shared_ptr<PathDiagnosticPiece>
-VirtualCallChecker::VirtualBugVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &) {
- // We need the last ctor/dtor which call the virtual function.
- // The visitor walks the ExplodedGraph backwards.
- if (Found)
- return nullptr;
-
- ProgramStateRef State = N->getState();
- const LocationContext *LCtx = N->getLocationContext();
- const CXXConstructorDecl *CD =
- dyn_cast_or_null<CXXConstructorDecl>(LCtx->getDecl());
- const CXXDestructorDecl *DD =
- dyn_cast_or_null<CXXDestructorDecl>(LCtx->getDecl());
-
- if (!CD && !DD)
- return nullptr;
-
- ProgramStateManager &PSM = State->getStateManager();
- auto &SVB = PSM.getSValBuilder();
- const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
- if (!MD)
- return nullptr;
- auto ThiSVal =
- State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
- const MemRegion *Reg = ThiSVal.castAs<loc::MemRegionVal>().getRegion();
- if (!Reg)
- return nullptr;
- if (Reg != ObjectRegion)
- return nullptr;
-
- const Stmt *S = PathDiagnosticLocation::getStmt(N);
- if (!S)
- return nullptr;
- Found = true;
-
- std::string InfoText;
- if (CD)
- InfoText = "This constructor of an object of type '" +
- CD->getNameAsString() +
- "' has not returned when the virtual method was called";
- else
- InfoText = "This destructor of an object of type '" +
- DD->getNameAsString() +
- "' has not returned when the virtual method was called";
-
- // Generate the extra diagnostic.
- PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
- N->getLocationContext());
- return std::make_shared<PathDiagnosticEventPiece>(Pos, InfoText, true);
-}
-
-// The function to check if a callexpr is a virtual function.
+// The function to check if a callexpr is a virtual method call.
static bool isVirtualCall(const CallExpr *CE) {
bool CallIsNonVirtual = false;
@@ -178,11 +103,10 @@ void VirtualCallChecker::checkPreCall(const CallEvent &Call,
const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Call.getDecl());
if (!MD)
return;
- ProgramStateRef State = C.getState();
- const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
- if (IsPureOnly && !MD->isPure())
- return;
+ ProgramStateRef State = C.getState();
+ // Member calls are always represented by a call-expression.
+ const auto *CE = cast<CallExpr>(Call.getOriginExpr());
if (!isVirtualCall(CE))
return;
@@ -190,29 +114,51 @@ void VirtualCallChecker::checkPreCall(const CallEvent &Call,
const ObjectState *ObState = State->get<CtorDtorMap>(Reg);
if (!ObState)
return;
- // Check if a virtual method is called.
- // The GDM of constructor and destructor should be true.
- if (*ObState == ObjectState::CtorCalled) {
- if (IsPureOnly && MD->isPure())
- reportBug("Call to pure virtual function during construction", true, Reg,
- C);
- else if (!MD->isPure())
- reportBug("Call to virtual function during construction", false, Reg, C);
- else
- reportBug("Call to pure virtual function during construction", false, Reg,
- C);
+
+ bool IsPure = MD->isPure();
+
+ // At this point we're sure that we're calling a virtual method
+ // during construction or destruction, so we'll emit a report.
+ SmallString<128> Msg;
+ llvm::raw_svector_ostream OS(Msg);
+ OS << "Call to ";
+ if (IsPure)
+ OS << "pure ";
+ OS << "virtual method '" << MD->getParent()->getNameAsString()
+ << "::" << MD->getNameAsString() << "' during ";
+ if (*ObState == ObjectState::CtorCalled)
+ OS << "construction ";
+ else
+ OS << "destruction ";
+ if (IsPure)
+ OS << "has undefined behavior";
+ else
+ OS << "bypasses virtual dispatch";
+
+ ExplodedNode *N =
+ IsPure ? C.generateErrorNode() : C.generateNonFatalErrorNode();
+ if (!N)
+ return;
+
+ const std::unique_ptr<BugType> &BT = IsPure ? BT_Pure : BT_Impure;
+ if (!BT) {
+ // The respective check is disabled.
+ return;
}
- if (*ObState == ObjectState::DtorCalled) {
- if (IsPureOnly && MD->isPure())
- reportBug("Call to pure virtual function during destruction", true, Reg,
- C);
- else if (!MD->isPure())
- reportBug("Call to virtual function during destruction", false, Reg, C);
- else
- reportBug("Call to pure virtual function during construction", false, Reg,
- C);
+ auto Report = std::make_unique<PathSensitiveBugReport>(*BT, OS.str(), N);
+
+ if (ShowFixIts && !IsPure) {
+ // FIXME: These hints are valid only when the virtual call is made
+ // directly from the constructor/destructor. Otherwise the dispatch
+ // will work just fine from other callees, and the fix may break
+ // the otherwise correct program.
+ FixItHint Fixit = FixItHint::CreateInsertion(
+ CE->getBeginLoc(), MD->getParent()->getNameAsString() + "::");
+ Report->addFixItHint(Fixit);
}
+
+ C.emitReport(std::move(Report));
}
void VirtualCallChecker::registerCtorDtorCallInState(bool IsBeginFunction,
@@ -254,34 +200,37 @@ void VirtualCallChecker::registerCtorDtorCallInState(bool IsBeginFunction,
}
}
-void VirtualCallChecker::reportBug(StringRef Msg, bool IsSink,
- const MemRegion *Reg,
- CheckerContext &C) const {
- ExplodedNode *N;
- if (IsSink)
- N = C.generateErrorNode();
- else
- N = C.generateNonFatalErrorNode();
+void ento::registerVirtualCallModeling(CheckerManager &Mgr) {
+ Mgr.registerChecker<VirtualCallChecker>();
+}
- if (!N)
- return;
- if (!BT)
- BT.reset(new BugType(
- this, "Call to virtual function during construction or destruction",
- "C++ Object Lifecycle"));
-
- auto Reporter = llvm::make_unique<BugReport>(*BT, Msg, N);
- Reporter->addVisitor(llvm::make_unique<VirtualBugVisitor>(Reg));
- C.emitReport(std::move(Reporter));
+void ento::registerPureVirtualCallChecker(CheckerManager &Mgr) {
+ auto *Chk = Mgr.getChecker<VirtualCallChecker>();
+ Chk->BT_Pure = std::make_unique<BugType>(Mgr.getCurrentCheckerName(),
+ "Pure virtual method call",
+ categories::CXXObjectLifecycle);
}
-void ento::registerVirtualCallChecker(CheckerManager &mgr) {
- VirtualCallChecker *checker = mgr.registerChecker<VirtualCallChecker>();
+void ento::registerVirtualCallChecker(CheckerManager &Mgr) {
+ auto *Chk = Mgr.getChecker<VirtualCallChecker>();
+ if (!Mgr.getAnalyzerOptions().getCheckerBooleanOption(
+ Mgr.getCurrentCheckerName(), "PureOnly")) {
+ Chk->BT_Impure = std::make_unique<BugType>(
+ Mgr.getCurrentCheckerName(), "Unexpected loss of virtual dispatch",
+ categories::CXXObjectLifecycle);
+ Chk->ShowFixIts = Mgr.getAnalyzerOptions().getCheckerBooleanOption(
+ Mgr.getCurrentCheckerName(), "ShowFixIts");
+ }
+}
+
+bool ento::shouldRegisterVirtualCallModeling(const LangOptions &LO) {
+ return LO.CPlusPlus;
+}
- checker->IsPureOnly =
- mgr.getAnalyzerOptions().getCheckerBooleanOption(checker, "PureOnly");
+bool ento::shouldRegisterPureVirtualCallChecker(const LangOptions &LO) {
+ return LO.CPlusPlus;
}
bool ento::shouldRegisterVirtualCallChecker(const LangOptions &LO) {
- return true;
+ return LO.CPlusPlus;
}
diff --git a/lib/StaticAnalyzer/Checkers/Yaml.h b/lib/StaticAnalyzer/Checkers/Yaml.h
new file mode 100755
index 000000000000..968c50e33f6d
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/Yaml.h
@@ -0,0 +1,59 @@
+//== Yaml.h ---------------------------------------------------- -*- C++ -*--=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines convenience functions for handling YAML configuration files
+// for checkers/packages.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKER_YAML_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKER_YAML_H
+
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "llvm/Support/YAMLTraits.h"
+
+namespace clang {
+namespace ento {
+
+/// Read the given file from the filesystem and parse it as a yaml file. The
+/// template parameter must have a yaml MappingTraits.
+/// Emit diagnostic error in case of any failure.
+template <class T, class Checker>
+llvm::Optional<T> getConfiguration(CheckerManager &Mgr, Checker *Chk,
+ StringRef Option, StringRef ConfigFile) {
+ if (ConfigFile.trim().empty())
+ return None;
+
+ llvm::vfs::FileSystem *FS = llvm::vfs::getRealFileSystem().get();
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
+ FS->getBufferForFile(ConfigFile.str());
+
+ if (std::error_code ec = Buffer.getError()) {
+ Mgr.reportInvalidCheckerOptionValue(Chk, Option,
+ "a valid filename instead of '" +
+ std::string(ConfigFile) + "'");
+ return None;
+ }
+
+ llvm::yaml::Input Input(Buffer.get()->getBuffer());
+ T Config;
+ Input >> Config;
+
+ if (std::error_code ec = Input.error()) {
+ Mgr.reportInvalidCheckerOptionValue(Chk, Option,
+ "a valid yaml file: " + ec.message());
+ return None;
+ }
+
+ return Config;
+}
+
+} // namespace ento
+} // namespace clang
+
+#endif // LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MOVE_H
diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index 1b1ffff5ade8..73e1a0d0000f 100644
--- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -13,7 +13,7 @@ using namespace ento;
void AnalysisManager::anchor() { }
-AnalysisManager::AnalysisManager(ASTContext &ASTCtx, DiagnosticsEngine &diags,
+AnalysisManager::AnalysisManager(ASTContext &ASTCtx,
const PathDiagnosticConsumers &PDC,
StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr,
@@ -38,7 +38,7 @@ AnalysisManager::AnalysisManager(ASTContext &ASTCtx, DiagnosticsEngine &diags,
Options.ShouldElideConstructors,
/*addVirtualBaseBranches=*/true,
injector),
- Ctx(ASTCtx), Diags(diags), LangOpts(ASTCtx.getLangOpts()),
+ Ctx(ASTCtx), LangOpts(ASTCtx.getLangOpts()),
PathConsumers(PDC), CreateStoreMgr(storemgr),
CreateConstraintMgr(constraintmgr), CheckerMgr(checkerMgr),
options(Options) {
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 71abe2ae6c0e..01ac2bc83bb6 100644
--- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -30,25 +30,6 @@ using namespace clang;
using namespace ento;
using namespace llvm;
-std::vector<StringRef>
-AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental /* = false */) {
- static const StringRef StaticAnalyzerChecks[] = {
-#define GET_CHECKERS
-#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \
- FULLNAME,
-#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
-#undef CHECKER
-#undef GET_CHECKERS
- };
- std::vector<StringRef> Result;
- for (StringRef CheckName : StaticAnalyzerChecks) {
- if (!CheckName.startswith("debug.") &&
- (IncludeExperimental || !CheckName.startswith("alpha.")))
- Result.push_back(CheckName);
- }
- return Result;
-}
-
void AnalyzerOptions::printFormattedEntry(
llvm::raw_ostream &Out,
std::pair<StringRef, StringRef> EntryDescPair,
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index e5a0794f10e2..1864bcef9b87 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -24,6 +24,7 @@
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
@@ -31,7 +32,6 @@
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
@@ -71,6 +71,7 @@
using namespace clang;
using namespace ento;
+using namespace llvm;
#define DEBUG_TYPE "BugReporter"
@@ -85,23 +86,252 @@ BugReporterVisitor::~BugReporterVisitor() = default;
void BugReporterContext::anchor() {}
//===----------------------------------------------------------------------===//
-// Helper routines for walking the ExplodedGraph and fetching statements.
+// PathDiagnosticBuilder and its associated routines and helper objects.
//===----------------------------------------------------------------------===//
-static const Stmt *GetPreviousStmt(const ExplodedNode *N) {
- for (N = N->getFirstPred(); N; N = N->getFirstPred())
- if (const Stmt *S = PathDiagnosticLocation::getStmt(N))
- return S;
+namespace {
- return nullptr;
+/// A (CallPiece, node assiciated with its CallEnter) pair.
+using CallWithEntry =
+ std::pair<PathDiagnosticCallPiece *, const ExplodedNode *>;
+using CallWithEntryStack = SmallVector<CallWithEntry, 6>;
+
+/// Map from each node to the diagnostic pieces visitors emit for them.
+using VisitorsDiagnosticsTy =
+ llvm::DenseMap<const ExplodedNode *, std::vector<PathDiagnosticPieceRef>>;
+
+/// A map from PathDiagnosticPiece to the LocationContext of the inlined
+/// function call it represents.
+using LocationContextMap =
+ llvm::DenseMap<const PathPieces *, const LocationContext *>;
+
+/// A helper class that contains everything needed to construct a
+/// PathDiagnostic object. It does no much more then providing convenient
+/// getters and some well placed asserts for extra security.
+class PathDiagnosticConstruct {
+ /// The consumer we're constructing the bug report for.
+ const PathDiagnosticConsumer *Consumer;
+ /// Our current position in the bug path, which is owned by
+ /// PathDiagnosticBuilder.
+ const ExplodedNode *CurrentNode;
+ /// A mapping from parts of the bug path (for example, a function call, which
+ /// would span backwards from a CallExit to a CallEnter with the nodes in
+ /// between them) with the location contexts it is associated with.
+ LocationContextMap LCM;
+ const SourceManager &SM;
+
+public:
+ /// We keep stack of calls to functions as we're ascending the bug path.
+ /// TODO: PathDiagnostic has a stack doing the same thing, shouldn't we use
+ /// that instead?
+ CallWithEntryStack CallStack;
+ /// The bug report we're constructing. For ease of use, this field is kept
+ /// public, though some "shortcut" getters are provided for commonly used
+ /// methods of PathDiagnostic.
+ std::unique_ptr<PathDiagnostic> PD;
+
+public:
+ PathDiagnosticConstruct(const PathDiagnosticConsumer *PDC,
+ const ExplodedNode *ErrorNode,
+ const PathSensitiveBugReport *R);
+
+ /// \returns the location context associated with the current position in the
+ /// bug path.
+ const LocationContext *getCurrLocationContext() const {
+ assert(CurrentNode && "Already reached the root!");
+ return CurrentNode->getLocationContext();
+ }
+
+ /// Same as getCurrLocationContext (they should always return the same
+ /// location context), but works after reaching the root of the bug path as
+ /// well.
+ const LocationContext *getLocationContextForActivePath() const {
+ return LCM.find(&PD->getActivePath())->getSecond();
+ }
+
+ const ExplodedNode *getCurrentNode() const { return CurrentNode; }
+
+ /// Steps the current node to its predecessor.
+ /// \returns whether we reached the root of the bug path.
+ bool ascendToPrevNode() {
+ CurrentNode = CurrentNode->getFirstPred();
+ return static_cast<bool>(CurrentNode);
+ }
+
+ const ParentMap &getParentMap() const {
+ return getCurrLocationContext()->getParentMap();
+ }
+
+ const SourceManager &getSourceManager() const { return SM; }
+
+ const Stmt *getParent(const Stmt *S) const {
+ return getParentMap().getParent(S);
+ }
+
+ void updateLocCtxMap(const PathPieces *Path, const LocationContext *LC) {
+ assert(Path && LC);
+ LCM[Path] = LC;
+ }
+
+ const LocationContext *getLocationContextFor(const PathPieces *Path) const {
+ assert(LCM.count(Path) &&
+ "Failed to find the context associated with these pieces!");
+ return LCM.find(Path)->getSecond();
+ }
+
+ bool isInLocCtxMap(const PathPieces *Path) const { return LCM.count(Path); }
+
+ PathPieces &getActivePath() { return PD->getActivePath(); }
+ PathPieces &getMutablePieces() { return PD->getMutablePieces(); }
+
+ bool shouldAddPathEdges() const { return Consumer->shouldAddPathEdges(); }
+ bool shouldGenerateDiagnostics() const {
+ return Consumer->shouldGenerateDiagnostics();
+ }
+ bool supportsLogicalOpControlFlow() const {
+ return Consumer->supportsLogicalOpControlFlow();
+ }
+};
+
+/// Contains every contextual information needed for constructing a
+/// PathDiagnostic object for a given bug report. This class and its fields are
+/// immutable, and passes a BugReportConstruct object around during the
+/// construction.
+class PathDiagnosticBuilder : public BugReporterContext {
+ /// A linear path from the error node to the root.
+ std::unique_ptr<const ExplodedGraph> BugPath;
+ /// The bug report we're describing. Visitors create their diagnostics with
+ /// them being the last entities being able to modify it (for example,
+ /// changing interestingness here would cause inconsistencies as to how this
+ /// file and visitors construct diagnostics), hence its const.
+ const PathSensitiveBugReport *R;
+ /// The leaf of the bug path. This isn't the same as the bug reports error
+ /// node, which refers to the *original* graph, not the bug path.
+ const ExplodedNode *const ErrorNode;
+ /// The diagnostic pieces visitors emitted, which is expected to be collected
+ /// by the time this builder is constructed.
+ std::unique_ptr<const VisitorsDiagnosticsTy> VisitorsDiagnostics;
+
+public:
+ /// Find a non-invalidated report for a given equivalence class, and returns
+ /// a PathDiagnosticBuilder able to construct bug reports for different
+ /// consumers. Returns None if no valid report is found.
+ static Optional<PathDiagnosticBuilder>
+ findValidReport(ArrayRef<PathSensitiveBugReport *> &bugReports,
+ PathSensitiveBugReporter &Reporter);
+
+ PathDiagnosticBuilder(
+ BugReporterContext BRC, std::unique_ptr<ExplodedGraph> BugPath,
+ PathSensitiveBugReport *r, const ExplodedNode *ErrorNode,
+ std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics);
+
+ /// This function is responsible for generating diagnostic pieces that are
+ /// *not* provided by bug report visitors.
+ /// These diagnostics may differ depending on the consumer's settings,
+ /// and are therefore constructed separately for each consumer.
+ ///
+ /// There are two path diagnostics generation modes: with adding edges (used
+ /// for plists) and without (used for HTML and text). When edges are added,
+ /// the path is modified to insert artificially generated edges.
+ /// Otherwise, more detailed diagnostics is emitted for block edges,
+ /// explaining the transitions in words.
+ std::unique_ptr<PathDiagnostic>
+ generate(const PathDiagnosticConsumer *PDC) const;
+
+private:
+ void updateStackPiecesWithMessage(PathDiagnosticPieceRef P,
+ const CallWithEntryStack &CallStack) const;
+ void generatePathDiagnosticsForNode(PathDiagnosticConstruct &C,
+ PathDiagnosticLocation &PrevLoc) const;
+
+ void generateMinimalDiagForBlockEdge(PathDiagnosticConstruct &C,
+ BlockEdge BE) const;
+
+ PathDiagnosticPieceRef
+ generateDiagForGotoOP(const PathDiagnosticConstruct &C, const Stmt *S,
+ PathDiagnosticLocation &Start) const;
+
+ PathDiagnosticPieceRef
+ generateDiagForSwitchOP(const PathDiagnosticConstruct &C, const CFGBlock *Dst,
+ PathDiagnosticLocation &Start) const;
+
+ PathDiagnosticPieceRef
+ generateDiagForBinaryOP(const PathDiagnosticConstruct &C, const Stmt *T,
+ const CFGBlock *Src, const CFGBlock *DstC) const;
+
+ PathDiagnosticLocation
+ ExecutionContinues(const PathDiagnosticConstruct &C) const;
+
+ PathDiagnosticLocation
+ ExecutionContinues(llvm::raw_string_ostream &os,
+ const PathDiagnosticConstruct &C) const;
+
+ const PathSensitiveBugReport *getBugReport() const { return R; }
+};
+
+} // namespace
+
+//===----------------------------------------------------------------------===//
+// Base implementation of stack hint generators.
+//===----------------------------------------------------------------------===//
+
+StackHintGenerator::~StackHintGenerator() = default;
+
+std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
+ if (!N)
+ return getMessageForSymbolNotFound();
+
+ ProgramPoint P = N->getLocation();
+ CallExitEnd CExit = P.castAs<CallExitEnd>();
+
+ // FIXME: Use CallEvent to abstract this over all calls.
+ const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
+ const auto *CE = dyn_cast_or_null<CallExpr>(CallSite);
+ if (!CE)
+ return {};
+
+ // Check if one of the parameters are set to the interesting symbol.
+ unsigned ArgIndex = 0;
+ for (CallExpr::const_arg_iterator I = CE->arg_begin(),
+ E = CE->arg_end(); I != E; ++I, ++ArgIndex){
+ SVal SV = N->getSVal(*I);
+
+ // 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 (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
+ // Do not attempt to dereference void*.
+ if ((*I)->getType()->isVoidPointerType())
+ continue;
+ SVal PSV = N->getState()->getSVal(Reg->getRegion());
+ SymbolRef AS = PSV.getAsLocSymbol();
+ if (AS == Sym) {
+ return getMessageForArg(*I, ArgIndex);
+ }
+ }
+ }
+
+ // Check if we are returning the interesting symbol.
+ SVal SV = N->getSVal(CE);
+ SymbolRef RetSym = SV.getAsLocSymbol();
+ if (RetSym == Sym) {
+ return getMessageForReturn(CE);
+ }
+
+ return getMessageForSymbolNotFound();
}
-static inline const Stmt*
-GetCurrentOrPreviousStmt(const ExplodedNode *N) {
- if (const Stmt *S = PathDiagnosticLocation::getStmt(N))
- return S;
+std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE,
+ unsigned ArgIndex) {
+ // Printed parameters start at 1, not 0.
+ ++ArgIndex;
- return GetPreviousStmt(N);
+ return (llvm::Twine(Msg) + " via " + std::to_string(ArgIndex) +
+ llvm::getOrdinalSuffix(ArgIndex) + " parameter").str();
}
//===----------------------------------------------------------------------===//
@@ -182,16 +412,12 @@ static void removeRedundantMsgs(PathPieces &path) {
}
}
-/// A map from PathDiagnosticPiece to the LocationContext of the inlined
-/// function call it represents.
-using LocationContextMap =
- llvm::DenseMap<const PathPieces *, const LocationContext *>;
-
/// 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 shouldn't be pruned from the parent path.
-static bool removeUnneededCalls(PathPieces &pieces, BugReport *R,
- LocationContextMap &LCM,
+static bool removeUnneededCalls(const PathDiagnosticConstruct &C,
+ PathPieces &pieces,
+ const PathSensitiveBugReport *R,
bool IsInteresting = false) {
bool containsSomethingInteresting = IsInteresting;
const unsigned N = pieces.size();
@@ -206,9 +432,9 @@ static bool removeUnneededCalls(PathPieces &pieces, BugReport *R,
case PathDiagnosticPiece::Call: {
auto &call = cast<PathDiagnosticCallPiece>(*piece);
// Check if the location context is interesting.
- assert(LCM.count(&call.path));
- if (!removeUnneededCalls(call.path, R, LCM,
- R->isInteresting(LCM[&call.path])))
+ if (!removeUnneededCalls(
+ C, call.path, R,
+ R->isInteresting(C.getLocationContextFor(&call.path))))
continue;
containsSomethingInteresting = true;
@@ -216,7 +442,7 @@ static bool removeUnneededCalls(PathPieces &pieces, BugReport *R,
}
case PathDiagnosticPiece::Macro: {
auto &macro = cast<PathDiagnosticMacroPiece>(*piece);
- if (!removeUnneededCalls(macro.subPieces, R, LCM, IsInteresting))
+ if (!removeUnneededCalls(C, macro.subPieces, R, IsInteresting))
continue;
containsSomethingInteresting = true;
break;
@@ -345,70 +571,23 @@ static void removePiecesWithInvalidLocations(PathPieces &Pieces) {
}
}
-//===----------------------------------------------------------------------===//
-// PathDiagnosticBuilder and its associated routines and helper objects.
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class PathDiagnosticBuilder : public BugReporterContext {
- BugReport *R;
- PathDiagnosticConsumer *PDC;
-
-public:
- const LocationContext *LC;
-
- PathDiagnosticBuilder(GRBugReporter &br,
- BugReport *r, InterExplodedGraphMap &Backmap,
- PathDiagnosticConsumer *pdc)
- : BugReporterContext(br, Backmap), R(r), PDC(pdc),
- LC(r->getErrorNode()->getLocationContext()) {}
+PathDiagnosticLocation PathDiagnosticBuilder::ExecutionContinues(
+ const PathDiagnosticConstruct &C) const {
+ if (const Stmt *S = C.getCurrentNode()->getNextStmtForDiagnostics())
+ return PathDiagnosticLocation(S, getSourceManager(),
+ C.getCurrLocationContext());
- PathDiagnosticLocation ExecutionContinues(const ExplodedNode *N);
-
- PathDiagnosticLocation ExecutionContinues(llvm::raw_string_ostream &os,
- const ExplodedNode *N);
-
- BugReport *getBugReport() { return R; }
-
- Decl const &getCodeDecl() { return R->getErrorNode()->getCodeDecl(); }
-
- ParentMap& getParentMap() { return LC->getParentMap(); }
-
- const Stmt *getParent(const Stmt *S) {
- return getParentMap().getParent(S);
- }
-
- PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S);
-
- PathDiagnosticConsumer::PathGenerationScheme getGenerationScheme() const {
- return PDC ? PDC->getGenerationScheme() : PathDiagnosticConsumer::Minimal;
- }
-
- bool supportsLogicalOpControlFlow() const {
- return PDC ? PDC->supportsLogicalOpControlFlow() : true;
- }
-};
-
-} // namespace
-
-PathDiagnosticLocation
-PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode *N) {
- if (const Stmt *S = PathDiagnosticLocation::getNextStmt(N))
- return PathDiagnosticLocation(S, getSourceManager(), LC);
-
- return PathDiagnosticLocation::createDeclEnd(N->getLocationContext(),
+ return PathDiagnosticLocation::createDeclEnd(C.getCurrLocationContext(),
getSourceManager());
}
-PathDiagnosticLocation
-PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream &os,
- const ExplodedNode *N) {
+PathDiagnosticLocation PathDiagnosticBuilder::ExecutionContinues(
+ llvm::raw_string_ostream &os, const PathDiagnosticConstruct &C) const {
// Slow, but probably doesn't matter.
if (os.str().empty())
os << ' ';
- const PathDiagnosticLocation &Loc = ExecutionContinues(N);
+ const PathDiagnosticLocation &Loc = ExecutionContinues(C);
if (Loc.asStmt())
os << "Execution continues on line "
@@ -416,7 +595,7 @@ PathDiagnosticBuilder::ExecutionContinues(llvm::raw_string_ostream &os,
<< '.';
else {
os << "Execution jumps to the end of the ";
- const Decl *D = N->getLocationContext()->getDecl();
+ const Decl *D = C.getCurrLocationContext()->getDecl();
if (isa<ObjCMethodDecl>(D))
os << "method";
else if (isa<FunctionDecl>(D))
@@ -454,12 +633,14 @@ static const Stmt *getEnclosingParent(const Stmt *S, const ParentMap &PM) {
}
static PathDiagnosticLocation
-getEnclosingStmtLocation(const Stmt *S, SourceManager &SMgr, const ParentMap &P,
- const LocationContext *LC, bool allowNestedContexts) {
+getEnclosingStmtLocation(const Stmt *S, const LocationContext *LC,
+ bool allowNestedContexts = false) {
if (!S)
return {};
- while (const Stmt *Parent = getEnclosingParent(S, P)) {
+ const SourceManager &SMgr = LC->getDecl()->getASTContext().getSourceManager();
+
+ while (const Stmt *Parent = getEnclosingParent(S, LC->getParentMap())) {
switch (Parent->getStmtClass()) {
case Stmt::BinaryOperatorClass: {
const auto *B = cast<BinaryOperator>(Parent);
@@ -520,59 +701,51 @@ getEnclosingStmtLocation(const Stmt *S, SourceManager &SMgr, const ParentMap &P,
return PathDiagnosticLocation(S, SMgr, LC);
}
-PathDiagnosticLocation
-PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
- assert(S && "Null Stmt passed to getEnclosingStmtLocation");
- return ::getEnclosingStmtLocation(S, getSourceManager(), getParentMap(), LC,
- /*allowNestedContexts=*/false);
-}
-
//===----------------------------------------------------------------------===//
// "Minimal" path diagnostic generation algorithm.
//===----------------------------------------------------------------------===//
-using StackDiagPair =
- std::pair<PathDiagnosticCallPiece *, const ExplodedNode *>;
-using StackDiagVector = SmallVector<StackDiagPair, 6>;
-
-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 (auto *ep = dyn_cast<PathDiagnosticEventPiece>(&P)) {
- if (ep->hasCallStackHint())
- for (const auto &I : CallStack) {
- 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);
- }
- }
+
+/// If the piece contains a special message, add it to all the call pieces on
+/// the active stack. For example, my_malloc allocated memory, so MallocChecker
+/// will construct an event at the call to malloc(), and add a stack hint that
+/// an allocated memory was returned. We'll use this hint to construct a message
+/// when returning from the call to my_malloc
+///
+/// void *my_malloc() { return malloc(sizeof(int)); }
+/// void fishy() {
+/// void *ptr = my_malloc(); // returned allocated memory
+/// } // leak
+void PathDiagnosticBuilder::updateStackPiecesWithMessage(
+ PathDiagnosticPieceRef P, const CallWithEntryStack &CallStack) const {
+ if (R->hasCallStackHint(P))
+ for (const auto &I : CallStack) {
+ PathDiagnosticCallPiece *CP = I.first;
+ const ExplodedNode *N = I.second;
+ std::string stackMsg = R->getCallStackMessage(P, 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 CompactMacroExpandedPieces(PathPieces &path,
const SourceManager& SM);
+PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForSwitchOP(
+ const PathDiagnosticConstruct &C, const CFGBlock *Dst,
+ PathDiagnosticLocation &Start) const {
-std::shared_ptr<PathDiagnosticControlFlowPiece> generateDiagForSwitchOP(
- const ExplodedNode *N,
- const CFGBlock *Dst,
- const SourceManager &SM,
- const LocationContext *LC,
- PathDiagnosticBuilder &PDB,
- PathDiagnosticLocation &Start
- ) {
+ const SourceManager &SM = getSourceManager();
// Figure out what case arm we took.
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
PathDiagnosticLocation End;
if (const Stmt *S = Dst->getLabel()) {
- End = PathDiagnosticLocation(S, SM, LC);
+ End = PathDiagnosticLocation(S, SM, C.getCurrLocationContext());
switch (S->getStmtClass()) {
default:
@@ -605,7 +778,7 @@ std::shared_ptr<PathDiagnosticControlFlowPiece> generateDiagForSwitchOP(
}
if (GetRawInt)
- os << LHS->EvaluateKnownConstInt(PDB.getASTContext());
+ os << LHS->EvaluateKnownConstInt(getASTContext());
os << ":' at line " << End.asLocation().getExpansionLineNumber();
break;
@@ -613,33 +786,29 @@ std::shared_ptr<PathDiagnosticControlFlowPiece> generateDiagForSwitchOP(
}
} else {
os << "'Default' branch taken. ";
- End = PDB.ExecutionContinues(os, N);
+ End = ExecutionContinues(os, C);
}
return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
os.str());
}
+PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForGotoOP(
+ const PathDiagnosticConstruct &C, const Stmt *S,
+ PathDiagnosticLocation &Start) const {
+ std::string sbuf;
+ llvm::raw_string_ostream os(sbuf);
+ const PathDiagnosticLocation &End =
+ getEnclosingStmtLocation(S, C.getCurrLocationContext());
+ os << "Control jumps to line " << End.asLocation().getExpansionLineNumber();
+ return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str());
+}
-std::shared_ptr<PathDiagnosticControlFlowPiece> generateDiagForGotoOP(
- const Stmt *S,
- PathDiagnosticBuilder &PDB,
- PathDiagnosticLocation &Start) {
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
- const PathDiagnosticLocation &End = PDB.getEnclosingStmtLocation(S);
- os << "Control jumps to line " << End.asLocation().getExpansionLineNumber();
- return std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str());
+PathDiagnosticPieceRef PathDiagnosticBuilder::generateDiagForBinaryOP(
+ const PathDiagnosticConstruct &C, const Stmt *T, const CFGBlock *Src,
+ const CFGBlock *Dst) const {
-}
+ const SourceManager &SM = getSourceManager();
-std::shared_ptr<PathDiagnosticControlFlowPiece> generateDiagForBinaryOP(
- const ExplodedNode *N,
- const Stmt *T,
- const CFGBlock *Src,
- const CFGBlock *Dst,
- const SourceManager &SM,
- PathDiagnosticBuilder &PDB,
- const LocationContext *LC) {
const auto *B = cast<BinaryOperator>(T);
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
@@ -652,13 +821,14 @@ std::shared_ptr<PathDiagnosticControlFlowPiece> generateDiagForBinaryOP(
if (*(Src->succ_begin() + 1) == Dst) {
os << "false";
- End = PathDiagnosticLocation(B->getLHS(), SM, LC);
+ End = PathDiagnosticLocation(B->getLHS(), SM, C.getCurrLocationContext());
Start =
PathDiagnosticLocation::createOperatorLoc(B, SM);
} else {
os << "true";
- Start = PathDiagnosticLocation(B->getLHS(), SM, LC);
- End = PDB.ExecutionContinues(N);
+ Start =
+ PathDiagnosticLocation(B->getLHS(), SM, C.getCurrLocationContext());
+ End = ExecutionContinues(C);
}
} else {
assert(B->getOpcode() == BO_LOr);
@@ -667,11 +837,12 @@ std::shared_ptr<PathDiagnosticControlFlowPiece> generateDiagForBinaryOP(
if (*(Src->succ_begin() + 1) == Dst) {
os << "false";
- Start = PathDiagnosticLocation(B->getLHS(), SM, LC);
- End = PDB.ExecutionContinues(N);
+ Start =
+ PathDiagnosticLocation(B->getLHS(), SM, C.getCurrLocationContext());
+ End = ExecutionContinues(C);
} else {
os << "true";
- End = PathDiagnosticLocation(B->getLHS(), SM, LC);
+ End = PathDiagnosticLocation(B->getLHS(), SM, C.getCurrLocationContext());
Start =
PathDiagnosticLocation::createOperatorLoc(B, SM);
}
@@ -680,11 +851,10 @@ std::shared_ptr<PathDiagnosticControlFlowPiece> generateDiagForBinaryOP(
os.str());
}
-void generateMinimalDiagForBlockEdge(const ExplodedNode *N, BlockEdge BE,
- const SourceManager &SM,
- PathDiagnosticBuilder &PDB,
- PathDiagnostic &PD) {
- const LocationContext *LC = N->getLocationContext();
+void PathDiagnosticBuilder::generateMinimalDiagForBlockEdge(
+ PathDiagnosticConstruct &C, BlockEdge BE) const {
+ const SourceManager &SM = getSourceManager();
+ const LocationContext *LC = C.getCurrLocationContext();
const CFGBlock *Src = BE.getSrc();
const CFGBlock *Dst = BE.getDst();
const Stmt *T = Src->getTerminatorStmt();
@@ -698,14 +868,13 @@ void generateMinimalDiagForBlockEdge(const ExplodedNode *N, BlockEdge BE,
case Stmt::GotoStmtClass:
case Stmt::IndirectGotoStmtClass: {
- if (const Stmt *S = PathDiagnosticLocation::getNextStmt(N))
- PD.getActivePath().push_front(generateDiagForGotoOP(S, PDB, Start));
+ if (const Stmt *S = C.getCurrentNode()->getNextStmtForDiagnostics())
+ C.getActivePath().push_front(generateDiagForGotoOP(C, S, Start));
break;
}
case Stmt::SwitchStmtClass: {
- PD.getActivePath().push_front(
- generateDiagForSwitchOP(N, Dst, SM, LC, PDB, Start));
+ C.getActivePath().push_front(generateDiagForSwitchOP(C, Dst, Start));
break;
}
@@ -713,8 +882,8 @@ void generateMinimalDiagForBlockEdge(const ExplodedNode *N, BlockEdge BE,
case Stmt::ContinueStmtClass: {
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
- PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
- PD.getActivePath().push_front(
+ PathDiagnosticLocation End = ExecutionContinues(os, C);
+ C.getActivePath().push_front(
std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str()));
break;
}
@@ -731,24 +900,22 @@ void generateMinimalDiagForBlockEdge(const ExplodedNode *N, BlockEdge BE,
else
os << "true";
- PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+ PathDiagnosticLocation End = ExecutionContinues(C);
if (const Stmt *S = End.asStmt())
- End = PDB.getEnclosingStmtLocation(S);
+ End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
- PD.getActivePath().push_front(
+ C.getActivePath().push_front(
std::make_shared<PathDiagnosticControlFlowPiece>(Start, End, os.str()));
break;
}
// Determine control-flow for short-circuited '&&' and '||'.
case Stmt::BinaryOperatorClass: {
- if (!PDB.supportsLogicalOpControlFlow())
+ if (!C.supportsLogicalOpControlFlow())
break;
- std::shared_ptr<PathDiagnosticControlFlowPiece> Diag =
- generateDiagForBinaryOP(N, T, Src, Dst, SM, PDB, LC);
- PD.getActivePath().push_front(Diag);
+ C.getActivePath().push_front(generateDiagForBinaryOP(C, T, Src, Dst));
break;
}
@@ -758,21 +925,21 @@ void generateMinimalDiagForBlockEdge(const ExplodedNode *N, BlockEdge BE,
llvm::raw_string_ostream os(sbuf);
os << "Loop condition is true. ";
- PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
+ PathDiagnosticLocation End = ExecutionContinues(os, C);
if (const Stmt *S = End.asStmt())
- End = PDB.getEnclosingStmtLocation(S);
+ End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
- PD.getActivePath().push_front(
+ C.getActivePath().push_front(
std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
os.str()));
} else {
- PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+ PathDiagnosticLocation End = ExecutionContinues(C);
if (const Stmt *S = End.asStmt())
- End = PDB.getEnclosingStmtLocation(S);
+ End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
- PD.getActivePath().push_front(
+ C.getActivePath().push_front(
std::make_shared<PathDiagnosticControlFlowPiece>(
Start, End, "Loop condition is false. Exiting loop"));
}
@@ -785,19 +952,19 @@ void generateMinimalDiagForBlockEdge(const ExplodedNode *N, BlockEdge BE,
llvm::raw_string_ostream os(sbuf);
os << "Loop condition is false. ";
- PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
+ PathDiagnosticLocation End = ExecutionContinues(os, C);
if (const Stmt *S = End.asStmt())
- End = PDB.getEnclosingStmtLocation(S);
+ End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
- PD.getActivePath().push_front(
+ C.getActivePath().push_front(
std::make_shared<PathDiagnosticControlFlowPiece>(Start, End,
os.str()));
} else {
- PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+ PathDiagnosticLocation End = ExecutionContinues(C);
if (const Stmt *S = End.asStmt())
- End = PDB.getEnclosingStmtLocation(S);
+ End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
- PD.getActivePath().push_front(
+ C.getActivePath().push_front(
std::make_shared<PathDiagnosticControlFlowPiece>(
Start, End, "Loop condition is true. Entering loop body"));
}
@@ -805,17 +972,17 @@ void generateMinimalDiagForBlockEdge(const ExplodedNode *N, BlockEdge BE,
break;
case Stmt::IfStmtClass: {
- PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+ PathDiagnosticLocation End = ExecutionContinues(C);
if (const Stmt *S = End.asStmt())
- End = PDB.getEnclosingStmtLocation(S);
+ End = getEnclosingStmtLocation(S, C.getCurrLocationContext());
if (*(Src->succ_begin() + 1) == Dst)
- PD.getActivePath().push_front(
+ C.getActivePath().push_front(
std::make_shared<PathDiagnosticControlFlowPiece>(
Start, End, "Taking false branch"));
else
- PD.getActivePath().push_front(
+ C.getActivePath().push_front(
std::make_shared<PathDiagnosticControlFlowPiece>(
Start, End, "Taking true branch"));
@@ -824,75 +991,6 @@ void generateMinimalDiagForBlockEdge(const ExplodedNode *N, BlockEdge BE,
}
}
-// Cone-of-influence: support the reverse propagation of "interesting" symbols
-// and values by tracing interesting calculations backwards through evaluated
-// expressions along a path. This is probably overly complicated, but the idea
-// is that if an expression computed an "interesting" value, the child
-// expressions are also likely to be "interesting" as well (which then
-// propagates to the values they in turn compute). This reverse propagation
-// is needed to track interesting correlations across function call boundaries,
-// where formal arguments bind to actual arguments, etc. This is also needed
-// because the constraint solver sometimes simplifies certain symbolic values
-// into constants when appropriate, and this complicates reasoning about
-// interesting values.
-using InterestingExprs = llvm::DenseSet<const Expr *>;
-
-static void reversePropagateIntererstingSymbols(BugReport &R,
- InterestingExprs &IE,
- const ProgramState *State,
- const Expr *Ex,
- const LocationContext *LCtx) {
- SVal V = State->getSVal(Ex, LCtx);
- if (!(R.isInteresting(V) || IE.count(Ex)))
- return;
-
- switch (Ex->getStmtClass()) {
- default:
- if (!isa<CastExpr>(Ex))
- break;
- LLVM_FALLTHROUGH;
- case Stmt::BinaryOperatorClass:
- case Stmt::UnaryOperatorClass: {
- for (const Stmt *SubStmt : Ex->children()) {
- if (const auto *child = dyn_cast_or_null<Expr>(SubStmt)) {
- IE.insert(child);
- SVal ChildV = State->getSVal(child, LCtx);
- R.markInteresting(ChildV);
- }
- }
- break;
- }
- }
-
- R.markInteresting(V);
-}
-
-static void reversePropagateInterestingSymbols(BugReport &R,
- InterestingExprs &IE,
- const ProgramState *State,
- const LocationContext *CalleeCtx)
-{
- // FIXME: Handle non-CallExpr-based CallEvents.
- const StackFrameContext *Callee = CalleeCtx->getStackFrame();
- const Stmt *CallSite = Callee->getCallSite();
- if (const auto *CE = dyn_cast_or_null<CallExpr>(CallSite)) {
- if (const auto *FD = dyn_cast<FunctionDecl>(CalleeCtx->getDecl())) {
- FunctionDecl::param_const_iterator PI = FD->param_begin(),
- PE = FD->param_end();
- CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end();
- for (; AI != AE && PI != PE; ++AI, ++PI) {
- if (const Expr *ArgE = *AI) {
- if (const ParmVarDecl *PD = *PI) {
- Loc LV = State->getLValue(PD, CalleeCtx);
- if (R.isInteresting(LV) || R.isInteresting(State->getRawSVal(LV)))
- IE.insert(ArgE);
- }
- }
- }
- }
- }
-}
-
//===----------------------------------------------------------------------===//
// Functions for determining if a loop was executed 0 times.
//===----------------------------------------------------------------------===//
@@ -916,7 +1014,8 @@ static bool isJumpToFalseBranch(const BlockEdge *BE) {
return (*(Src->succ_begin()+1) == BE->getDst());
}
-static bool isContainedByStmt(ParentMap &PM, const Stmt *S, const Stmt *SubS) {
+static bool isContainedByStmt(const ParentMap &PM, const Stmt *S,
+ const Stmt *SubS) {
while (SubS) {
if (SubS == S)
return true;
@@ -925,7 +1024,7 @@ static bool isContainedByStmt(ParentMap &PM, const Stmt *S, const Stmt *SubS) {
return false;
}
-static const Stmt *getStmtBeforeCond(ParentMap &PM, const Stmt *Term,
+static const Stmt *getStmtBeforeCond(const ParentMap &PM, const Stmt *Term,
const ExplodedNode *N) {
while (N) {
Optional<StmtPoint> SP = N->getLocation().getAs<StmtPoint>();
@@ -939,7 +1038,7 @@ static const Stmt *getStmtBeforeCond(ParentMap &PM, const Stmt *Term,
return nullptr;
}
-static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term) {
+static bool isInLoopBody(const ParentMap &PM, const Stmt *S, const Stmt *Term) {
const Stmt *LoopBody = nullptr;
switch (Term->getStmtClass()) {
case Stmt::CXXForRangeStmtClass: {
@@ -1007,30 +1106,20 @@ static const Stmt *getTerminatorCondition(const CFGBlock *B) {
return S;
}
-static const char StrEnteringLoop[] = "Entering loop body";
-static const char StrLoopBodyZero[] = "Loop body executed 0 times";
-static const char StrLoopRangeEmpty[] =
- "Loop body skipped when range is empty";
-static const char StrLoopCollectionEmpty[] =
- "Loop body skipped when collection is empty";
+constexpr llvm::StringLiteral StrEnteringLoop = "Entering loop body";
+constexpr llvm::StringLiteral StrLoopBodyZero = "Loop body executed 0 times";
+constexpr llvm::StringLiteral StrLoopRangeEmpty =
+ "Loop body skipped when range is empty";
+constexpr llvm::StringLiteral StrLoopCollectionEmpty =
+ "Loop body skipped when collection is empty";
static std::unique_ptr<FilesToLineNumsMap>
-findExecutedLines(SourceManager &SM, const ExplodedNode *N);
-
-/// Generate diagnostics for the node \p N,
-/// and write it into \p PD.
-/// \p AddPathEdges Whether diagnostic consumer can generate path arrows
-/// showing both row and column.
-static void generatePathDiagnosticsForNode(const ExplodedNode *N,
- PathDiagnostic &PD,
- PathDiagnosticLocation &PrevLoc,
- PathDiagnosticBuilder &PDB,
- LocationContextMap &LCM,
- StackDiagVector &CallStack,
- InterestingExprs &IE,
- bool AddPathEdges) {
- ProgramPoint P = N->getLocation();
- const SourceManager& SM = PDB.getSourceManager();
+findExecutedLines(const SourceManager &SM, const ExplodedNode *N);
+
+void PathDiagnosticBuilder::generatePathDiagnosticsForNode(
+ PathDiagnosticConstruct &C, PathDiagnosticLocation &PrevLoc) const {
+ ProgramPoint P = C.getCurrentNode()->getLocation();
+ const SourceManager &SM = getSourceManager();
// Have we encountered an entrance to a call? It may be
// the case that we have not encountered a matching
@@ -1038,7 +1127,7 @@ static void generatePathDiagnosticsForNode(const ExplodedNode *N,
// terminated within the call itself.
if (auto CE = P.getAs<CallEnter>()) {
- if (AddPathEdges) {
+ if (C.shouldAddPathEdges()) {
// Add an edge to the start of the function.
const StackFrameContext *CalleeLC = CE->getCalleeContext();
const Decl *D = CalleeLC->getDecl();
@@ -1049,139 +1138,105 @@ static void generatePathDiagnosticsForNode(const ExplodedNode *N,
// because the exit edge comes from a statement (i.e. return),
// not from declaration.
if (D->hasBody())
- addEdgeToPath(PD.getActivePath(), PrevLoc,
- PathDiagnosticLocation::createBegin(D, SM));
+ addEdgeToPath(C.getActivePath(), PrevLoc,
+ PathDiagnosticLocation::createBegin(D, SM));
}
// Did we visit an entire call?
- bool VisitedEntireCall = PD.isWithinCall();
- PD.popActivePath();
+ bool VisitedEntireCall = C.PD->isWithinCall();
+ C.PD->popActivePath();
- PathDiagnosticCallPiece *C;
+ PathDiagnosticCallPiece *Call;
if (VisitedEntireCall) {
- C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front().get());
+ Call = cast<PathDiagnosticCallPiece>(C.getActivePath().front().get());
} else {
+ // The path terminated within a nested location context, create a new
+ // call piece to encapsulate the rest of the path pieces.
const Decl *Caller = CE->getLocationContext()->getDecl();
- C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller);
-
- if (AddPathEdges) {
- // Since we just transferred the path over to the call piece,
- // reset the mapping from active to location context.
- assert(PD.getActivePath().size() == 1 &&
- PD.getActivePath().front().get() == C);
- LCM[&PD.getActivePath()] = nullptr;
- }
-
- // Record the location context mapping for the path within
- // the call.
- assert(LCM[&C->path] == nullptr ||
- LCM[&C->path] == CE->getCalleeContext());
- LCM[&C->path] = CE->getCalleeContext();
-
- // If this is the first item in the active path, record
- // the new mapping from active path to location context.
- const LocationContext *&NewLC = LCM[&PD.getActivePath()];
- if (!NewLC)
- NewLC = N->getLocationContext();
-
- PDB.LC = NewLC;
- }
- C->setCallee(*CE, SM);
+ Call = PathDiagnosticCallPiece::construct(C.getActivePath(), Caller);
+ assert(C.getActivePath().size() == 1 &&
+ C.getActivePath().front().get() == Call);
+
+ // Since we just transferred the path over to the call piece, reset the
+ // mapping of the active path to the current location context.
+ assert(C.isInLocCtxMap(&C.getActivePath()) &&
+ "When we ascend to a previously unvisited call, the active path's "
+ "address shouldn't change, but rather should be compacted into "
+ "a single CallEvent!");
+ C.updateLocCtxMap(&C.getActivePath(), C.getCurrLocationContext());
+
+ // Record the location context mapping for the path within the call.
+ assert(!C.isInLocCtxMap(&Call->path) &&
+ "When we ascend to a previously unvisited call, this must be the "
+ "first time we encounter the caller context!");
+ C.updateLocCtxMap(&Call->path, CE->getCalleeContext());
+ }
+ Call->setCallee(*CE, SM);
// Update the previous location in the active path.
- PrevLoc = C->getLocation();
+ PrevLoc = Call->getLocation();
- if (!CallStack.empty()) {
- assert(CallStack.back().first == C);
- CallStack.pop_back();
+ if (!C.CallStack.empty()) {
+ assert(C.CallStack.back().first == Call);
+ C.CallStack.pop_back();
}
return;
}
-
- if (AddPathEdges) {
- // Query the location context here and the previous location
- // as processing CallEnter may change the active path.
- PDB.LC = N->getLocationContext();
-
- // Record the mapping from the active path to the location
- // context.
- assert(!LCM[&PD.getActivePath()] || LCM[&PD.getActivePath()] == PDB.LC);
- LCM[&PD.getActivePath()] = PDB.LC;
- }
+ assert(C.getCurrLocationContext() == C.getLocationContextForActivePath() &&
+ "The current position in the bug path is out of sync with the "
+ "location context associated with the active path!");
// Have we encountered an exit from a function call?
if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
// We are descending into a call (backwards). Construct
// a new call piece to contain the path pieces for that call.
- auto C = PathDiagnosticCallPiece::construct(*CE, SM);
+ auto Call = PathDiagnosticCallPiece::construct(*CE, SM);
// Record the mapping from call piece to LocationContext.
- LCM[&C->path] = CE->getCalleeContext();
-
- if (AddPathEdges) {
- const Stmt *S = CE->getCalleeContext()->getCallSite();
- // Propagate the interesting symbols accordingly.
- if (const auto *Ex = dyn_cast_or_null<Expr>(S)) {
- reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
- N->getState().get(), Ex,
- N->getLocationContext());
- }
+ assert(!C.isInLocCtxMap(&Call->path) &&
+ "We just entered a call, this must've been the first time we "
+ "encounter its context!");
+ C.updateLocCtxMap(&Call->path, CE->getCalleeContext());
+
+ if (C.shouldAddPathEdges()) {
// Add the edge to the return site.
- addEdgeToPath(PD.getActivePath(), PrevLoc, C->callReturn);
+ addEdgeToPath(C.getActivePath(), PrevLoc, Call->callReturn);
PrevLoc.invalidate();
}
- auto *P = C.get();
- PD.getActivePath().push_front(std::move(C));
+ auto *P = Call.get();
+ C.getActivePath().push_front(std::move(Call));
// Make the contents of the call the active path for now.
- PD.pushActivePath(&P->path);
- CallStack.push_back(StackDiagPair(P, N));
+ C.PD->pushActivePath(&P->path);
+ C.CallStack.push_back(CallWithEntry(P, C.getCurrentNode()));
return;
}
if (auto PS = P.getAs<PostStmt>()) {
- if (!AddPathEdges)
+ if (!C.shouldAddPathEdges())
return;
- // For expressions, make sure we propagate the
- // interesting symbols correctly.
- if (const Expr *Ex = PS->getStmtAs<Expr>())
- reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
- N->getState().get(), Ex,
- N->getLocationContext());
-
// Add an edge. If this is an ObjCForCollectionStmt do
// not add an edge here as it appears in the CFG both
// as a terminator and as a terminator condition.
if (!isa<ObjCForCollectionStmt>(PS->getStmt())) {
PathDiagnosticLocation L =
- PathDiagnosticLocation(PS->getStmt(), SM, PDB.LC);
- addEdgeToPath(PD.getActivePath(), PrevLoc, L);
+ PathDiagnosticLocation(PS->getStmt(), SM, C.getCurrLocationContext());
+ addEdgeToPath(C.getActivePath(), PrevLoc, L);
}
} else if (auto BE = P.getAs<BlockEdge>()) {
- if (!AddPathEdges) {
- generateMinimalDiagForBlockEdge(N, *BE, SM, PDB, PD);
+ if (!C.shouldAddPathEdges()) {
+ generateMinimalDiagForBlockEdge(C, *BE);
return;
}
- // Does this represent entering a call? If so, look at propagating
- // interesting symbols across call boundaries.
- if (const ExplodedNode *NextNode = N->getFirstPred()) {
- const LocationContext *CallerCtx = NextNode->getLocationContext();
- const LocationContext *CalleeCtx = PDB.LC;
- if (CallerCtx != CalleeCtx && AddPathEdges) {
- reversePropagateInterestingSymbols(*PDB.getBugReport(), IE,
- N->getState().get(), CalleeCtx);
- }
- }
-
// Are we jumping to the head of a loop? Add a special diagnostic.
if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
- PathDiagnosticLocation L(Loop, SM, PDB.LC);
+ PathDiagnosticLocation L(Loop, SM, C.getCurrLocationContext());
const Stmt *Body = nullptr;
if (const auto *FS = dyn_cast<ForStmt>(Loop))
@@ -1200,27 +1255,27 @@ static void generatePathDiagnosticsForNode(const ExplodedNode *N,
"of the loop");
p->setPrunable(true);
- addEdgeToPath(PD.getActivePath(), PrevLoc, p->getLocation());
- PD.getActivePath().push_front(std::move(p));
+ addEdgeToPath(C.getActivePath(), PrevLoc, p->getLocation());
+ C.getActivePath().push_front(std::move(p));
if (const auto *CS = dyn_cast_or_null<CompoundStmt>(Body)) {
- addEdgeToPath(PD.getActivePath(), PrevLoc,
- PathDiagnosticLocation::createEndBrace(CS, SM));
+ addEdgeToPath(C.getActivePath(), PrevLoc,
+ PathDiagnosticLocation::createEndBrace(CS, SM));
}
}
const CFGBlock *BSrc = BE->getSrc();
- ParentMap &PM = PDB.getParentMap();
+ const ParentMap &PM = C.getParentMap();
if (const Stmt *Term = BSrc->getTerminatorStmt()) {
// Are we jumping past the loop body without ever executing the
// loop (because the condition was false)?
if (isLoop(Term)) {
const Stmt *TermCond = getTerminatorCondition(BSrc);
- bool IsInLoopBody =
- isInLoopBody(PM, getStmtBeforeCond(PM, TermCond, N), Term);
+ bool IsInLoopBody = isInLoopBody(
+ PM, getStmtBeforeCond(PM, TermCond, C.getCurrentNode()), Term);
- const char *str = nullptr;
+ StringRef str;
if (isJumpToFalseBranch(&*BE)) {
if (!IsInLoopBody) {
@@ -1236,31 +1291,41 @@ static void generatePathDiagnosticsForNode(const ExplodedNode *N,
str = StrEnteringLoop;
}
- if (str) {
- PathDiagnosticLocation L(TermCond ? TermCond : Term, SM, PDB.LC);
+ if (!str.empty()) {
+ PathDiagnosticLocation L(TermCond ? TermCond : Term, SM,
+ C.getCurrLocationContext());
auto PE = std::make_shared<PathDiagnosticEventPiece>(L, str);
PE->setPrunable(true);
- addEdgeToPath(PD.getActivePath(), PrevLoc,
- PE->getLocation());
- PD.getActivePath().push_front(std::move(PE));
+ addEdgeToPath(C.getActivePath(), PrevLoc, PE->getLocation());
+ C.getActivePath().push_front(std::move(PE));
}
} else if (isa<BreakStmt>(Term) || isa<ContinueStmt>(Term) ||
isa<GotoStmt>(Term)) {
- PathDiagnosticLocation L(Term, SM, PDB.LC);
- addEdgeToPath(PD.getActivePath(), PrevLoc, L);
+ PathDiagnosticLocation L(Term, SM, C.getCurrLocationContext());
+ addEdgeToPath(C.getActivePath(), PrevLoc, L);
}
}
}
}
static std::unique_ptr<PathDiagnostic>
-generateEmptyDiagnosticForReport(BugReport *R, SourceManager &SM) {
+generateDiagnosticForBasicReport(const BasicBugReport *R) {
const BugType &BT = R->getBugType();
- return llvm::make_unique<PathDiagnostic>(
- R->getBugType().getCheckName(), R->getDeclWithIssue(),
- R->getBugType().getName(), R->getDescription(),
- R->getShortDescription(/*UseFallback=*/false), BT.getCategory(),
- R->getUniqueingLocation(), R->getUniqueingDecl(),
+ return std::make_unique<PathDiagnostic>(
+ BT.getCheckerName(), R->getDeclWithIssue(), BT.getDescription(),
+ R->getDescription(), R->getShortDescription(/*UseFallback=*/false),
+ BT.getCategory(), R->getUniqueingLocation(), R->getUniqueingDecl(),
+ std::make_unique<FilesToLineNumsMap>());
+}
+
+static std::unique_ptr<PathDiagnostic>
+generateEmptyDiagnosticForReport(const PathSensitiveBugReport *R,
+ const SourceManager &SM) {
+ const BugType &BT = R->getBugType();
+ return std::make_unique<PathDiagnostic>(
+ BT.getCheckerName(), R->getDeclWithIssue(), BT.getDescription(),
+ R->getDescription(), R->getShortDescription(/*UseFallback=*/false),
+ BT.getCategory(), R->getUniqueingLocation(), R->getUniqueingDecl(),
findExecutedLines(SM, R->getErrorNode()));
}
@@ -1342,8 +1407,8 @@ using OptimizedCallsSet = llvm::DenseSet<const PathDiagnosticCallPiece *>;
/// This avoids a "swoosh" effect, where an edge from a top-level statement A
/// points to a sub-expression B.1 that's not at the start of B. In these cases,
/// we'd like to see an edge from A to B, then another one from B to B.1.
-static void addContextEdges(PathPieces &pieces, SourceManager &SM,
- const ParentMap &PM, const LocationContext *LCtx) {
+static void addContextEdges(PathPieces &pieces, const LocationContext *LC) {
+ const ParentMap &PM = LC->getParentMap();
PathPieces::iterator Prev = pieces.end();
for (PathPieces::iterator I = pieces.begin(), E = Prev; I != E;
Prev = I, ++I) {
@@ -1360,7 +1425,7 @@ static void addContextEdges(PathPieces &pieces, SourceManager &SM,
while (NextSrcContext.isValid() && NextSrcContext.asStmt() != InnerStmt) {
SrcContexts.push_back(NextSrcContext);
InnerStmt = NextSrcContext.asStmt();
- NextSrcContext = getEnclosingStmtLocation(InnerStmt, SM, PM, LCtx,
+ NextSrcContext = getEnclosingStmtLocation(InnerStmt, LC,
/*allowNested=*/true);
}
@@ -1373,7 +1438,7 @@ static void addContextEdges(PathPieces &pieces, SourceManager &SM,
// We are looking at an edge. Is the destination within a larger
// expression?
PathDiagnosticLocation DstContext =
- getEnclosingStmtLocation(Dst, SM, PM, LCtx, /*allowNested=*/true);
+ getEnclosingStmtLocation(Dst, LC, /*allowNested=*/true);
if (!DstContext.isValid() || DstContext.asStmt() == Dst)
break;
@@ -1493,7 +1558,7 @@ static void simplifySimpleBranches(PathPieces &pieces) {
/// If the locations in the range are not on the same line, returns None.
///
/// Note that this does not do a precise user-visible character or column count.
-static Optional<size_t> getLengthOnSingleLine(SourceManager &SM,
+static Optional<size_t> getLengthOnSingleLine(const SourceManager &SM,
SourceRange Range) {
SourceRange ExpansionRange(SM.getExpansionLoc(Range.getBegin()),
SM.getExpansionRange(Range.getEnd()).getEnd());
@@ -1523,7 +1588,7 @@ static Optional<size_t> getLengthOnSingleLine(SourceManager &SM,
}
/// \sa getLengthOnSingleLine(SourceManager, SourceRange)
-static Optional<size_t> getLengthOnSingleLine(SourceManager &SM,
+static Optional<size_t> getLengthOnSingleLine(const SourceManager &SM,
const Stmt *S) {
return getLengthOnSingleLine(SM, S->getSourceRange());
}
@@ -1544,7 +1609,7 @@ static Optional<size_t> getLengthOnSingleLine(SourceManager &SM,
/// - if there is an inlined call between the edges instead of a single event.
/// - if the whole statement is large enough that having subexpression arrows
/// might be helpful.
-static void removeContextCycles(PathPieces &Path, SourceManager &SM) {
+static void removeContextCycles(PathPieces &Path, const SourceManager &SM) {
for (PathPieces::iterator I = Path.begin(), E = Path.end(); I != E; ) {
// Pattern match the current piece and its successor.
const auto *PieceI = dyn_cast<PathDiagnosticControlFlowPiece>(I->get());
@@ -1599,7 +1664,7 @@ static void removeContextCycles(PathPieces &Path, SourceManager &SM) {
}
/// Return true if X is contained by Y.
-static bool lexicalContains(ParentMap &PM, const Stmt *X, const Stmt *Y) {
+static bool lexicalContains(const ParentMap &PM, const Stmt *X, const Stmt *Y) {
while (X) {
if (X == Y)
return true;
@@ -1609,8 +1674,8 @@ static bool lexicalContains(ParentMap &PM, const Stmt *X, const Stmt *Y) {
}
// Remove short edges on the same line less than 3 columns in difference.
-static void removePunyEdges(PathPieces &path, SourceManager &SM,
- ParentMap &PM) {
+static void removePunyEdges(PathPieces &path, const SourceManager &SM,
+ const ParentMap &PM) {
bool erased = false;
for (PathPieces::iterator I = path.begin(), E = path.end(); I != E;
@@ -1685,13 +1750,13 @@ static void removeIdenticalEvents(PathPieces &path) {
}
}
-static bool optimizeEdges(PathPieces &path, SourceManager &SM,
- OptimizedCallsSet &OCS,
- LocationContextMap &LCM) {
+static bool optimizeEdges(const PathDiagnosticConstruct &C, PathPieces &path,
+ OptimizedCallsSet &OCS) {
bool hasChanges = false;
- const LocationContext *LC = LCM[&path];
+ const LocationContext *LC = C.getLocationContextFor(&path);
assert(LC);
- ParentMap &PM = LC->getParentMap();
+ const ParentMap &PM = LC->getParentMap();
+ const SourceManager &SM = C.getSourceManager();
for (PathPieces::iterator I = path.begin(), E = path.end(); I != E; ) {
// Optimize subpaths.
@@ -1699,7 +1764,8 @@ static bool optimizeEdges(PathPieces &path, SourceManager &SM,
// Record the fact that a call has been optimized so we only do the
// effort once.
if (!OCS.count(CallI)) {
- while (optimizeEdges(CallI->path, SM, OCS, LCM)) {}
+ while (optimizeEdges(C, CallI->path, OCS)) {
+ }
OCS.insert(CallI);
}
++I;
@@ -1845,7 +1911,7 @@ static bool optimizeEdges(PathPieces &path, SourceManager &SM,
if (!hasChanges) {
// Adjust edges into subexpressions to make them more uniform
// and aesthetically pleasing.
- addContextEdges(path, SM, PM, LC);
+ addContextEdges(path, LC);
// Remove "cyclical" edges that include one or more context edges.
removeContextCycles(path, SM);
// Hoist edges originating from branch conditions to branches
@@ -1866,27 +1932,24 @@ static bool optimizeEdges(PathPieces &path, SourceManager &SM,
/// statement had an invalid source location), this function does nothing.
// FIXME: We should just generate invalid edges anyway and have the optimizer
// deal with them.
-static void dropFunctionEntryEdge(PathPieces &Path, LocationContextMap &LCM,
- SourceManager &SM) {
+static void dropFunctionEntryEdge(const PathDiagnosticConstruct &C,
+ PathPieces &Path) {
const auto *FirstEdge =
dyn_cast<PathDiagnosticControlFlowPiece>(Path.front().get());
if (!FirstEdge)
return;
- const Decl *D = LCM[&Path]->getDecl();
- PathDiagnosticLocation EntryLoc = PathDiagnosticLocation::createBegin(D, SM);
+ const Decl *D = C.getLocationContextFor(&Path)->getDecl();
+ PathDiagnosticLocation EntryLoc =
+ PathDiagnosticLocation::createBegin(D, C.getSourceManager());
if (FirstEdge->getStartLocation() != EntryLoc)
return;
Path.pop_front();
}
-using VisitorsDiagnosticsTy = llvm::DenseMap<const ExplodedNode *,
- std::vector<std::shared_ptr<PathDiagnosticPiece>>>;
-
/// Populate executes lines with lines containing at least one diagnostics.
-static void updateExecutedLinesWithDiagnosticPieces(
- PathDiagnostic &PD) {
+static void updateExecutedLinesWithDiagnosticPieces(PathDiagnostic &PD) {
PathPieces path = PD.path.flatten(/*ShouldFlattenMacros=*/true);
FilesToLineNumsMap &ExecutedLines = PD.getExecutedLines();
@@ -1900,56 +1963,61 @@ static void updateExecutedLinesWithDiagnosticPieces(
}
}
-/// This function is responsible for generating diagnostic pieces that are
-/// *not* provided by bug report visitors.
-/// These diagnostics may differ depending on the consumer's settings,
-/// and are therefore constructed separately for each consumer.
-///
-/// There are two path diagnostics generation modes: with adding edges (used
-/// for plists) and without (used for HTML and text).
-/// When edges are added (\p ActiveScheme is Extensive),
-/// the path is modified to insert artificially generated
-/// edges.
-/// Otherwise, more detailed diagnostics is emitted for block edges, explaining
-/// the transitions in words.
-static std::unique_ptr<PathDiagnostic> generatePathDiagnosticForConsumer(
- PathDiagnosticConsumer::PathGenerationScheme ActiveScheme,
- PathDiagnosticBuilder &PDB,
- const ExplodedNode *ErrorNode,
- const VisitorsDiagnosticsTy &VisitorsDiagnostics) {
-
- bool GenerateDiagnostics = (ActiveScheme != PathDiagnosticConsumer::None);
- bool AddPathEdges = (ActiveScheme == PathDiagnosticConsumer::Extensive);
- SourceManager &SM = PDB.getSourceManager();
- BugReport *R = PDB.getBugReport();
- AnalyzerOptions &Opts = PDB.getBugReporter().getAnalyzerOptions();
- StackDiagVector CallStack;
- InterestingExprs IE;
- LocationContextMap LCM;
- std::unique_ptr<PathDiagnostic> PD = generateEmptyDiagnosticForReport(R, SM);
-
- if (GenerateDiagnostics) {
- auto EndNotes = VisitorsDiagnostics.find(ErrorNode);
- std::shared_ptr<PathDiagnosticPiece> LastPiece;
- if (EndNotes != VisitorsDiagnostics.end()) {
- assert(!EndNotes->second.empty());
- LastPiece = EndNotes->second[0];
- } else {
- LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, ErrorNode, *R);
- }
- PD->setEndOfPath(LastPiece);
+PathDiagnosticConstruct::PathDiagnosticConstruct(
+ const PathDiagnosticConsumer *PDC, const ExplodedNode *ErrorNode,
+ const PathSensitiveBugReport *R)
+ : Consumer(PDC), CurrentNode(ErrorNode),
+ SM(CurrentNode->getCodeDecl().getASTContext().getSourceManager()),
+ PD(generateEmptyDiagnosticForReport(R, getSourceManager())) {
+ LCM[&PD->getActivePath()] = ErrorNode->getLocationContext();
+}
+
+PathDiagnosticBuilder::PathDiagnosticBuilder(
+ BugReporterContext BRC, std::unique_ptr<ExplodedGraph> BugPath,
+ PathSensitiveBugReport *r, const ExplodedNode *ErrorNode,
+ std::unique_ptr<VisitorsDiagnosticsTy> VisitorsDiagnostics)
+ : BugReporterContext(BRC), BugPath(std::move(BugPath)), R(r),
+ ErrorNode(ErrorNode),
+ VisitorsDiagnostics(std::move(VisitorsDiagnostics)) {}
+
+std::unique_ptr<PathDiagnostic>
+PathDiagnosticBuilder::generate(const PathDiagnosticConsumer *PDC) const {
+ PathDiagnosticConstruct Construct(PDC, ErrorNode, R);
+
+ const SourceManager &SM = getSourceManager();
+ const AnalyzerOptions &Opts = getAnalyzerOptions();
+ StringRef ErrorTag = ErrorNode->getLocation().getTag()->getTagDescription();
+
+ // See whether we need to silence the checker/package.
+ // FIXME: This will not work if the report was emitted with an incorrect tag.
+ for (const std::string &CheckerOrPackage : Opts.SilencedCheckersAndPackages) {
+ if (ErrorTag.startswith(CheckerOrPackage))
+ return nullptr;
}
- PathDiagnosticLocation PrevLoc = PD->getLocation();
- const ExplodedNode *NextNode = ErrorNode->getFirstPred();
- while (NextNode) {
- if (GenerateDiagnostics)
- generatePathDiagnosticsForNode(
- NextNode, *PD, PrevLoc, PDB, LCM, CallStack, IE, AddPathEdges);
+ if (!PDC->shouldGenerateDiagnostics())
+ return generateEmptyDiagnosticForReport(R, getSourceManager());
+
+ // Construct the final (warning) event for the bug report.
+ auto EndNotes = VisitorsDiagnostics->find(ErrorNode);
+ PathDiagnosticPieceRef LastPiece;
+ if (EndNotes != VisitorsDiagnostics->end()) {
+ assert(!EndNotes->second.empty());
+ LastPiece = EndNotes->second[0];
+ } else {
+ LastPiece = BugReporterVisitor::getDefaultEndPath(*this, ErrorNode,
+ *getBugReport());
+ }
+ Construct.PD->setEndOfPath(LastPiece);
+
+ PathDiagnosticLocation PrevLoc = Construct.PD->getLocation();
+ // From the error node to the root, ascend the bug path and construct the bug
+ // report.
+ while (Construct.ascendToPrevNode()) {
+ generatePathDiagnosticsForNode(Construct, PrevLoc);
- auto VisitorNotes = VisitorsDiagnostics.find(NextNode);
- NextNode = NextNode->getFirstPred();
- if (!GenerateDiagnostics || VisitorNotes == VisitorsDiagnostics.end())
+ auto VisitorNotes = VisitorsDiagnostics->find(Construct.getCurrentNode());
+ if (VisitorNotes == VisitorsDiagnostics->end())
continue;
// This is a workaround due to inability to put shared PathDiagnosticPiece
@@ -1957,74 +2025,74 @@ static std::unique_ptr<PathDiagnostic> generatePathDiagnosticForConsumer(
std::set<llvm::FoldingSetNodeID> DeduplicationSet;
// Add pieces from custom visitors.
- for (const auto &Note : VisitorNotes->second) {
+ for (const PathDiagnosticPieceRef &Note : VisitorNotes->second) {
llvm::FoldingSetNodeID ID;
Note->Profile(ID);
- auto P = DeduplicationSet.insert(ID);
- if (!P.second)
+ if (!DeduplicationSet.insert(ID).second)
continue;
- if (AddPathEdges)
- addEdgeToPath(PD->getActivePath(), PrevLoc, Note->getLocation());
- updateStackPiecesWithMessage(*Note, CallStack);
- PD->getActivePath().push_front(Note);
+ if (PDC->shouldAddPathEdges())
+ addEdgeToPath(Construct.getActivePath(), PrevLoc, Note->getLocation());
+ updateStackPiecesWithMessage(Note, Construct.CallStack);
+ Construct.getActivePath().push_front(Note);
}
}
- if (AddPathEdges) {
+ if (PDC->shouldAddPathEdges()) {
// Add an edge to the start of the function.
// We'll prune it out later, but it helps make diagnostics more uniform.
- const StackFrameContext *CalleeLC = PDB.LC->getStackFrame();
+ const StackFrameContext *CalleeLC =
+ Construct.getLocationContextForActivePath()->getStackFrame();
const Decl *D = CalleeLC->getDecl();
- addEdgeToPath(PD->getActivePath(), PrevLoc,
+ addEdgeToPath(Construct.getActivePath(), PrevLoc,
PathDiagnosticLocation::createBegin(D, SM));
}
// Finally, prune the diagnostic path of uninteresting stuff.
- if (!PD->path.empty()) {
+ if (!Construct.PD->path.empty()) {
if (R->shouldPrunePath() && Opts.ShouldPrunePaths) {
bool stillHasNotes =
- removeUnneededCalls(PD->getMutablePieces(), R, LCM);
+ removeUnneededCalls(Construct, Construct.getMutablePieces(), R);
assert(stillHasNotes);
(void)stillHasNotes;
}
// Remove pop-up notes if needed.
if (!Opts.ShouldAddPopUpNotes)
- removePopUpNotes(PD->getMutablePieces());
+ removePopUpNotes(Construct.getMutablePieces());
// Redirect all call pieces to have valid locations.
- adjustCallLocations(PD->getMutablePieces());
- removePiecesWithInvalidLocations(PD->getMutablePieces());
+ adjustCallLocations(Construct.getMutablePieces());
+ removePiecesWithInvalidLocations(Construct.getMutablePieces());
- if (AddPathEdges) {
+ if (PDC->shouldAddPathEdges()) {
// Reduce the number of edges from a very conservative set
// to an aesthetically pleasing subset that conveys the
// necessary information.
OptimizedCallsSet OCS;
- while (optimizeEdges(PD->getMutablePieces(), SM, OCS, LCM)) {}
+ while (optimizeEdges(Construct, Construct.getMutablePieces(), OCS)) {
+ }
// Drop the very first function-entry edge. It's not really necessary
// for top-level functions.
- dropFunctionEntryEdge(PD->getMutablePieces(), LCM, SM);
+ dropFunctionEntryEdge(Construct, Construct.getMutablePieces());
}
// Remove messages that are basically the same, and edges that may not
// make sense.
// We have to do this after edge optimization in the Extensive mode.
- removeRedundantMsgs(PD->getMutablePieces());
- removeEdgesToDefaultInitializers(PD->getMutablePieces());
+ removeRedundantMsgs(Construct.getMutablePieces());
+ removeEdgesToDefaultInitializers(Construct.getMutablePieces());
}
- if (GenerateDiagnostics && Opts.ShouldDisplayMacroExpansions)
- CompactMacroExpandedPieces(PD->getMutablePieces(), SM);
+ if (Opts.ShouldDisplayMacroExpansions)
+ CompactMacroExpandedPieces(Construct.getMutablePieces(), SM);
- return PD;
+ return std::move(Construct.PD);
}
-
//===----------------------------------------------------------------------===//
// Methods for BugType and subclasses.
//===----------------------------------------------------------------------===//
@@ -2037,9 +2105,8 @@ void BuiltinBug::anchor() {}
// Methods for BugReport and subclasses.
//===----------------------------------------------------------------------===//
-void BugReport::NodeResolver::anchor() {}
-
-void BugReport::addVisitor(std::unique_ptr<BugReporterVisitor> visitor) {
+void PathSensitiveBugReport::addVisitor(
+ std::unique_ptr<BugReporterVisitor> visitor) {
if (!visitor)
return;
@@ -2054,20 +2121,11 @@ void BugReport::addVisitor(std::unique_ptr<BugReporterVisitor> visitor) {
Callbacks.push_back(std::move(visitor));
}
-void BugReport::clearVisitors() {
+void PathSensitiveBugReport::clearVisitors() {
Callbacks.clear();
}
-BugReport::~BugReport() {
- while (!interestingSymbols.empty()) {
- popInterestingSymbolsAndRegions();
- }
-}
-
-const Decl *BugReport::getDeclWithIssue() const {
- if (DeclWithIssue)
- return DeclWithIssue;
-
+const Decl *PathSensitiveBugReport::getDeclWithIssue() const {
const ExplodedNode *N = getErrorNode();
if (!N)
return nullptr;
@@ -2076,17 +2134,34 @@ const Decl *BugReport::getDeclWithIssue() const {
return LC->getStackFrame()->getDecl();
}
-void BugReport::Profile(llvm::FoldingSetNodeID& hash) const {
+void BasicBugReport::Profile(llvm::FoldingSetNodeID& hash) const {
+ hash.AddInteger(static_cast<int>(getKind()));
+ hash.AddPointer(&BT);
+ hash.AddString(Description);
+ assert(Location.isValid());
+ Location.Profile(hash);
+
+ for (SourceRange range : Ranges) {
+ if (!range.isValid())
+ continue;
+ hash.AddInteger(range.getBegin().getRawEncoding());
+ hash.AddInteger(range.getEnd().getRawEncoding());
+ }
+}
+
+void PathSensitiveBugReport::Profile(llvm::FoldingSetNodeID &hash) const {
+ hash.AddInteger(static_cast<int>(getKind()));
hash.AddPointer(&BT);
hash.AddString(Description);
PathDiagnosticLocation UL = getUniqueingLocation();
if (UL.isValid()) {
UL.Profile(hash);
- } else if (Location.isValid()) {
- Location.Profile(hash);
} else {
- assert(ErrorNode);
- hash.AddPointer(GetCurrentOrPreviousStmt(ErrorNode));
+ // TODO: The statement may be null if the report was emitted before any
+ // statements were executed. In particular, some checkers by design
+ // occasionally emit their reports in empty functions (that have no
+ // statements in their body). Do we profile correctly in this case?
+ hash.AddPointer(ErrorNode->getCurrentOrPreviousStmtForDiagnostics());
}
for (SourceRange range : Ranges) {
@@ -2097,96 +2172,141 @@ void BugReport::Profile(llvm::FoldingSetNodeID& hash) const {
}
}
-void BugReport::markInteresting(SymbolRef sym) {
+template <class T>
+static void insertToInterestingnessMap(
+ llvm::DenseMap<T, bugreporter::TrackingKind> &InterestingnessMap, T Val,
+ bugreporter::TrackingKind TKind) {
+ auto Result = InterestingnessMap.insert({Val, TKind});
+
+ if (Result.second)
+ return;
+
+ // Even if this symbol/region was already marked as interesting as a
+ // condition, if we later mark it as interesting again but with
+ // thorough tracking, overwrite it. Entities marked with thorough
+ // interestiness are the most important (or most interesting, if you will),
+ // and we wouldn't like to downplay their importance.
+
+ switch (TKind) {
+ case bugreporter::TrackingKind::Thorough:
+ Result.first->getSecond() = bugreporter::TrackingKind::Thorough;
+ return;
+ case bugreporter::TrackingKind::Condition:
+ return;
+ }
+
+ llvm_unreachable(
+ "BugReport::markInteresting currently can only handle 2 different "
+ "tracking kinds! Please define what tracking kind should this entitiy"
+ "have, if it was already marked as interesting with a different kind!");
+}
+
+void PathSensitiveBugReport::markInteresting(SymbolRef sym,
+ bugreporter::TrackingKind TKind) {
if (!sym)
return;
- getInterestingSymbols().insert(sym);
+ insertToInterestingnessMap(InterestingSymbols, sym, TKind);
if (const auto *meta = dyn_cast<SymbolMetadata>(sym))
- getInterestingRegions().insert(meta->getRegion());
+ markInteresting(meta->getRegion(), TKind);
}
-void BugReport::markInteresting(const MemRegion *R) {
+void PathSensitiveBugReport::markInteresting(const MemRegion *R,
+ bugreporter::TrackingKind TKind) {
if (!R)
return;
R = R->getBaseRegion();
- getInterestingRegions().insert(R);
+ insertToInterestingnessMap(InterestingRegions, R, TKind);
if (const auto *SR = dyn_cast<SymbolicRegion>(R))
- getInterestingSymbols().insert(SR->getSymbol());
+ markInteresting(SR->getSymbol(), TKind);
}
-void BugReport::markInteresting(SVal V) {
- markInteresting(V.getAsRegion());
- markInteresting(V.getAsSymbol());
+void PathSensitiveBugReport::markInteresting(SVal V,
+ bugreporter::TrackingKind TKind) {
+ markInteresting(V.getAsRegion(), TKind);
+ markInteresting(V.getAsSymbol(), TKind);
}
-void BugReport::markInteresting(const LocationContext *LC) {
+void PathSensitiveBugReport::markInteresting(const LocationContext *LC) {
if (!LC)
return;
InterestingLocationContexts.insert(LC);
}
-bool BugReport::isInteresting(SVal V) {
- return isInteresting(V.getAsRegion()) || isInteresting(V.getAsSymbol());
+Optional<bugreporter::TrackingKind>
+PathSensitiveBugReport::getInterestingnessKind(SVal V) const {
+ auto RKind = getInterestingnessKind(V.getAsRegion());
+ auto SKind = getInterestingnessKind(V.getAsSymbol());
+ if (!RKind)
+ return SKind;
+ if (!SKind)
+ return RKind;
+
+ // If either is marked with throrough tracking, return that, we wouldn't like
+ // to downplay a note's importance by 'only' mentioning it as a condition.
+ switch(*RKind) {
+ case bugreporter::TrackingKind::Thorough:
+ return RKind;
+ case bugreporter::TrackingKind::Condition:
+ return SKind;
+ }
+
+ llvm_unreachable(
+ "BugReport::getInterestingnessKind currently can only handle 2 different "
+ "tracking kinds! Please define what tracking kind should we return here "
+ "when the kind of getAsRegion() and getAsSymbol() is different!");
+ return None;
}
-bool BugReport::isInteresting(SymbolRef sym) {
+Optional<bugreporter::TrackingKind>
+PathSensitiveBugReport::getInterestingnessKind(SymbolRef sym) const {
if (!sym)
- return false;
+ return None;
// We don't currently consider metadata symbols to be interesting
// even if we know their region is interesting. Is that correct behavior?
- return getInterestingSymbols().count(sym);
+ auto It = InterestingSymbols.find(sym);
+ if (It == InterestingSymbols.end())
+ return None;
+ return It->getSecond();
}
-bool BugReport::isInteresting(const MemRegion *R) {
+Optional<bugreporter::TrackingKind>
+PathSensitiveBugReport::getInterestingnessKind(const MemRegion *R) const {
if (!R)
- return false;
- R = R->getBaseRegion();
- bool b = getInterestingRegions().count(R);
- if (b)
- return true;
- if (const auto *SR = dyn_cast<SymbolicRegion>(R))
- return getInterestingSymbols().count(SR->getSymbol());
- return false;
-}
+ return None;
-bool BugReport::isInteresting(const LocationContext *LC) {
- if (!LC)
- return false;
- return InterestingLocationContexts.count(LC);
-}
+ R = R->getBaseRegion();
+ auto It = InterestingRegions.find(R);
+ if (It != InterestingRegions.end())
+ return It->getSecond();
-void BugReport::lazyInitializeInterestingSets() {
- if (interestingSymbols.empty()) {
- interestingSymbols.push_back(new Symbols());
- interestingRegions.push_back(new Regions());
- }
+ if (const auto *SR = dyn_cast<SymbolicRegion>(R))
+ return getInterestingnessKind(SR->getSymbol());
+ return None;
}
-BugReport::Symbols &BugReport::getInterestingSymbols() {
- lazyInitializeInterestingSets();
- return *interestingSymbols.back();
+bool PathSensitiveBugReport::isInteresting(SVal V) const {
+ return getInterestingnessKind(V).hasValue();
}
-BugReport::Regions &BugReport::getInterestingRegions() {
- lazyInitializeInterestingSets();
- return *interestingRegions.back();
+bool PathSensitiveBugReport::isInteresting(SymbolRef sym) const {
+ return getInterestingnessKind(sym).hasValue();
}
-void BugReport::pushInterestingSymbolsAndRegions() {
- interestingSymbols.push_back(new Symbols(getInterestingSymbols()));
- interestingRegions.push_back(new Regions(getInterestingRegions()));
+bool PathSensitiveBugReport::isInteresting(const MemRegion *R) const {
+ return getInterestingnessKind(R).hasValue();
}
-void BugReport::popInterestingSymbolsAndRegions() {
- delete interestingSymbols.pop_back_val();
- delete interestingRegions.pop_back_val();
+bool PathSensitiveBugReport::isInteresting(const LocationContext *LC) const {
+ if (!LC)
+ return false;
+ return InterestingLocationContexts.count(LC);
}
-const Stmt *BugReport::getStmt() const {
+const Stmt *PathSensitiveBugReport::getStmt() const {
if (!ErrorNode)
return nullptr;
@@ -2196,59 +2316,83 @@ const Stmt *BugReport::getStmt() const {
if (Optional<BlockEntrance> BE = ProgP.getAs<BlockEntrance>()) {
CFGBlock &Exit = ProgP.getLocationContext()->getCFG()->getExit();
if (BE->getBlock() == &Exit)
- S = GetPreviousStmt(ErrorNode);
+ S = ErrorNode->getPreviousStmtForDiagnostics();
}
if (!S)
- S = PathDiagnosticLocation::getStmt(ErrorNode);
+ S = ErrorNode->getStmtForDiagnostics();
return S;
}
-llvm::iterator_range<BugReport::ranges_iterator> BugReport::getRanges() {
+ArrayRef<SourceRange>
+PathSensitiveBugReport::getRanges() const {
// If no custom ranges, add the range of the statement corresponding to
// the error node.
- if (Ranges.empty()) {
- if (const auto *E = dyn_cast_or_null<Expr>(getStmt()))
- addRange(E->getSourceRange());
- else
- return llvm::make_range(ranges_iterator(), ranges_iterator());
+ if (Ranges.empty() && isa_and_nonnull<Expr>(getStmt()))
+ return ErrorNodeRange;
+
+ return Ranges;
+}
+
+PathDiagnosticLocation
+PathSensitiveBugReport::getLocation() const {
+ assert(ErrorNode && "Cannot create a location with a null node.");
+ const Stmt *S = ErrorNode->getStmtForDiagnostics();
+ ProgramPoint P = ErrorNode->getLocation();
+ const LocationContext *LC = P.getLocationContext();
+ SourceManager &SM =
+ ErrorNode->getState()->getStateManager().getContext().getSourceManager();
+
+ if (!S) {
+ // If this is an implicit call, return the implicit call point location.
+ if (Optional<PreImplicitCall> PIE = P.getAs<PreImplicitCall>())
+ return PathDiagnosticLocation(PIE->getLocation(), SM);
+ if (auto FE = P.getAs<FunctionExitPoint>()) {
+ if (const ReturnStmt *RS = FE->getStmt())
+ return PathDiagnosticLocation::createBegin(RS, SM, LC);
+ }
+ S = ErrorNode->getNextStmtForDiagnostics();
}
- // User-specified absence of range info.
- if (Ranges.size() == 1 && !Ranges.begin()->isValid())
- return llvm::make_range(ranges_iterator(), ranges_iterator());
+ if (S) {
+ // For member expressions, return the location of the '.' or '->'.
+ if (const auto *ME = dyn_cast<MemberExpr>(S))
+ return PathDiagnosticLocation::createMemberLoc(ME, SM);
- return llvm::make_range(Ranges.begin(), Ranges.end());
-}
+ // For binary operators, return the location of the operator.
+ if (const auto *B = dyn_cast<BinaryOperator>(S))
+ return PathDiagnosticLocation::createOperatorLoc(B, SM);
+
+ if (P.getAs<PostStmtPurgeDeadSymbols>())
+ return PathDiagnosticLocation::createEnd(S, SM, LC);
+
+ if (S->getBeginLoc().isValid())
+ return PathDiagnosticLocation(S, SM, LC);
-PathDiagnosticLocation BugReport::getLocation(const SourceManager &SM) const {
- if (ErrorNode) {
- assert(!Location.isValid() &&
- "Either Location or ErrorNode should be specified but not both.");
- return PathDiagnosticLocation::createEndOfPath(ErrorNode, SM);
+ return PathDiagnosticLocation(
+ PathDiagnosticLocation::getValidSourceLocation(S, LC), SM);
}
- assert(Location.isValid());
- return Location;
+ return PathDiagnosticLocation::createDeclEnd(ErrorNode->getLocationContext(),
+ SM);
}
//===----------------------------------------------------------------------===//
// Methods for BugReporter and subclasses.
//===----------------------------------------------------------------------===//
-BugReportEquivClass::~BugReportEquivClass() = default;
-
-GRBugReporter::~GRBugReporter() = default;
-
-BugReporterData::~BugReporterData() = default;
-
-ExplodedGraph &GRBugReporter::getGraph() { return Eng.getGraph(); }
+const ExplodedGraph &PathSensitiveBugReporter::getGraph() const {
+ return Eng.getGraph();
+}
-ProgramStateManager&
-GRBugReporter::getStateManager() { return Eng.getStateManager(); }
+ProgramStateManager &PathSensitiveBugReporter::getStateManager() const {
+ return Eng.getStateManager();
+}
BugReporter::~BugReporter() {
- FlushReports();
+ // Make sure reports are flushed.
+ assert(StrBugTypes.empty() &&
+ "Destroying BugReporter before diagnostics are emitted!");
// Free the bug reports we are tracking.
for (const auto I : EQClassesVector)
@@ -2256,9 +2400,6 @@ BugReporter::~BugReporter() {
}
void BugReporter::FlushReports() {
- if (BugTypes.isEmpty())
- return;
-
// We need to flush reports in deterministic order to ensure the order
// of the reports is consistent between runs.
for (const auto EQ : EQClassesVector)
@@ -2269,9 +2410,6 @@ void BugReporter::FlushReports() {
// FIXME: There are leaks from checkers that assume that the BugTypes they
// create will be destroyed by the BugReporter.
llvm::DeleteContainerSeconds(StrBugTypes);
-
- // Remove all references to the BugType objects.
- BugTypes = F.getEmptySet();
}
//===----------------------------------------------------------------------===//
@@ -2280,29 +2418,32 @@ void BugReporter::FlushReports() {
namespace {
-/// A wrapper around a report graph, which contains only a single path, and its
-/// node maps.
-class ReportGraph {
+/// A wrapper around an ExplodedGraph that contains a single path from the root
+/// to the error node.
+class BugPathInfo {
public:
- InterExplodedGraphMap BackMap;
- std::unique_ptr<ExplodedGraph> Graph;
+ std::unique_ptr<ExplodedGraph> BugPath;
+ PathSensitiveBugReport *Report;
const ExplodedNode *ErrorNode;
- size_t Index;
};
-/// A wrapper around a trimmed graph and its node maps.
-class TrimmedGraph {
- InterExplodedGraphMap InverseMap;
+/// A wrapper around an ExplodedGraph whose leafs are all error nodes. Can
+/// conveniently retrieve bug paths from a single error node to the root.
+class BugPathGetter {
+ std::unique_ptr<ExplodedGraph> TrimmedGraph;
using PriorityMapTy = llvm::DenseMap<const ExplodedNode *, unsigned>;
+ /// Assign each node with its distance from the root.
PriorityMapTy PriorityMap;
- using NodeIndexPair = std::pair<const ExplodedNode *, size_t>;
-
- SmallVector<NodeIndexPair, 32> ReportNodes;
+ /// Since the getErrorNode() or BugReport refers to the original ExplodedGraph,
+ /// we need to pair it to the error node of the constructed trimmed graph.
+ using ReportNewNodePair =
+ std::pair<PathSensitiveBugReport *, const ExplodedNode *>;
+ SmallVector<ReportNewNodePair, 32> ReportNodes;
- std::unique_ptr<ExplodedGraph> G;
+ BugPathInfo CurrentBugPath;
/// A helper class for sorting ExplodedNodes by priority.
template <bool Descending>
@@ -2326,37 +2467,48 @@ class TrimmedGraph {
: LI->second < RI->second;
}
- bool operator()(const NodeIndexPair &LHS, const NodeIndexPair &RHS) const {
- return (*this)(LHS.first, RHS.first);
+ bool operator()(const ReportNewNodePair &LHS,
+ const ReportNewNodePair &RHS) const {
+ return (*this)(LHS.second, RHS.second);
}
};
public:
- TrimmedGraph(const ExplodedGraph *OriginalGraph,
- ArrayRef<const ExplodedNode *> Nodes);
+ BugPathGetter(const ExplodedGraph *OriginalGraph,
+ ArrayRef<PathSensitiveBugReport *> &bugReports);
- bool popNextReportGraph(ReportGraph &GraphWrapper);
+ BugPathInfo *getNextBugPath();
};
} // namespace
-TrimmedGraph::TrimmedGraph(const ExplodedGraph *OriginalGraph,
- ArrayRef<const ExplodedNode *> Nodes) {
+BugPathGetter::BugPathGetter(const ExplodedGraph *OriginalGraph,
+ ArrayRef<PathSensitiveBugReport *> &bugReports) {
+ SmallVector<const ExplodedNode *, 32> Nodes;
+ for (const auto I : bugReports) {
+ assert(I->isValid() &&
+ "We only allow BugReporterVisitors and BugReporter itself to "
+ "invalidate reports!");
+ Nodes.emplace_back(I->getErrorNode());
+ }
+
// The trimmed graph is created in the body of the constructor to ensure
// that the DenseMaps have been initialized already.
InterExplodedGraphMap ForwardMap;
- G = OriginalGraph->trim(Nodes, &ForwardMap, &InverseMap);
+ TrimmedGraph = OriginalGraph->trim(Nodes, &ForwardMap);
// Find the (first) error node in the trimmed graph. We just need to consult
// the node map which maps from nodes in the original graph to nodes
// in the new graph.
llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;
- for (unsigned i = 0, count = Nodes.size(); i < count; ++i) {
- if (const ExplodedNode *NewNode = ForwardMap.lookup(Nodes[i])) {
- ReportNodes.push_back(std::make_pair(NewNode, i));
- RemainingNodes.insert(NewNode);
- }
+ for (PathSensitiveBugReport *Report : bugReports) {
+ const ExplodedNode *NewNode = ForwardMap.lookup(Report->getErrorNode());
+ assert(NewNode &&
+ "Failed to construct a trimmed graph that contains this error "
+ "node!");
+ ReportNodes.emplace_back(Report, NewNode);
+ RemainingNodes.insert(NewNode);
}
assert(!RemainingNodes.empty() && "No error node found in the trimmed graph");
@@ -2364,8 +2516,8 @@ TrimmedGraph::TrimmedGraph(const ExplodedGraph *OriginalGraph,
// Perform a forward BFS to find all the shortest paths.
std::queue<const ExplodedNode *> WS;
- assert(G->num_roots() == 1);
- WS.push(*G->roots_begin());
+ assert(TrimmedGraph->num_roots() == 1);
+ WS.push(*TrimmedGraph->roots_begin());
unsigned Priority = 0;
while (!WS.empty()) {
@@ -2374,8 +2526,7 @@ TrimmedGraph::TrimmedGraph(const ExplodedGraph *OriginalGraph,
PriorityMapTy::iterator PriorityEntry;
bool IsNew;
- std::tie(PriorityEntry, IsNew) =
- PriorityMap.insert(std::make_pair(Node, Priority));
+ std::tie(PriorityEntry, IsNew) = PriorityMap.insert({Node, Priority});
++Priority;
if (!IsNew) {
@@ -2387,29 +2538,26 @@ TrimmedGraph::TrimmedGraph(const ExplodedGraph *OriginalGraph,
if (RemainingNodes.empty())
break;
- for (ExplodedNode::const_pred_iterator I = Node->succ_begin(),
- E = Node->succ_end();
- I != E; ++I)
- WS.push(*I);
+ for (const ExplodedNode *Succ : Node->succs())
+ WS.push(Succ);
}
// Sort the error paths from longest to shortest.
llvm::sort(ReportNodes, PriorityCompare<true>(PriorityMap));
}
-bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) {
+BugPathInfo *BugPathGetter::getNextBugPath() {
if (ReportNodes.empty())
- return false;
+ return nullptr;
const ExplodedNode *OrigN;
- std::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val();
+ std::tie(CurrentBugPath.Report, OrigN) = ReportNodes.pop_back_val();
assert(PriorityMap.find(OrigN) != PriorityMap.end() &&
"error node not accessible from root");
- // Create a new graph with a single path. This is the graph
- // that will be returned to the caller.
- auto GNew = llvm::make_unique<ExplodedGraph>();
- GraphWrapper.BackMap.clear();
+ // Create a new graph with a single path. This is the graph that will be
+ // returned to the caller.
+ auto GNew = std::make_unique<ExplodedGraph>();
// Now walk from the error node up the BFS path, always taking the
// predeccessor with the lowest number.
@@ -2417,19 +2565,15 @@ bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) {
while (true) {
// Create the equivalent node in the new graph with the same state
// and location.
- ExplodedNode *NewN = GNew->createUncachedNode(OrigN->getLocation(), OrigN->getState(),
- OrigN->isSink());
-
- // Store the mapping to the original node.
- InterExplodedGraphMap::const_iterator IMitr = InverseMap.find(OrigN);
- assert(IMitr != InverseMap.end() && "No mapping to original node.");
- GraphWrapper.BackMap[NewN] = IMitr->second;
+ ExplodedNode *NewN = GNew->createUncachedNode(
+ OrigN->getLocation(), OrigN->getState(),
+ OrigN->getID(), OrigN->isSink());
// Link up the new node with the previous node.
if (Succ)
Succ->addPredecessor(NewN, *GNew);
else
- GraphWrapper.ErrorNode = NewN;
+ CurrentBugPath.ErrorNode = NewN;
Succ = NewN;
@@ -2442,23 +2586,22 @@ bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) {
// Find the next predeccessor node. We choose the node that is marked
// with the lowest BFS number.
OrigN = *std::min_element(OrigN->pred_begin(), OrigN->pred_end(),
- PriorityCompare<false>(PriorityMap));
+ PriorityCompare<false>(PriorityMap));
}
- GraphWrapper.Graph = std::move(GNew);
+ CurrentBugPath.BugPath = std::move(GNew);
- return true;
+ return &CurrentBugPath;
}
/// CompactMacroExpandedPieces - This function postprocesses a PathDiagnostic
/// object and collapses PathDiagosticPieces that are expanded by macros.
static void CompactMacroExpandedPieces(PathPieces &path,
const SourceManager& SM) {
- using MacroStackTy =
- std::vector<
- std::pair<std::shared_ptr<PathDiagnosticMacroPiece>, SourceLocation>>;
+ using MacroStackTy = std::vector<
+ std::pair<std::shared_ptr<PathDiagnosticMacroPiece>, SourceLocation>>;
- using PiecesTy = std::vector<std::shared_ptr<PathDiagnosticPiece>>;
+ using PiecesTy = std::vector<PathDiagnosticPieceRef>;
MacroStackTy MacroStack;
PiecesTy Pieces;
@@ -2548,33 +2691,39 @@ static void CompactMacroExpandedPieces(PathPieces &path,
/// Notes associated with {@code ErrorNode} are generated using
/// {@code getEndPath}, and the rest are generated with {@code VisitNode}.
static std::unique_ptr<VisitorsDiagnosticsTy>
-generateVisitorsDiagnostics(BugReport *R, const ExplodedNode *ErrorNode,
+generateVisitorsDiagnostics(PathSensitiveBugReport *R,
+ const ExplodedNode *ErrorNode,
BugReporterContext &BRC) {
- auto Notes = llvm::make_unique<VisitorsDiagnosticsTy>();
- BugReport::VisitorList visitors;
+ std::unique_ptr<VisitorsDiagnosticsTy> Notes =
+ std::make_unique<VisitorsDiagnosticsTy>();
+ PathSensitiveBugReport::VisitorList visitors;
// Run visitors on all nodes starting from the node *before* the last one.
// The last node is reserved for notes generated with {@code getEndPath}.
const ExplodedNode *NextNode = ErrorNode->getFirstPred();
while (NextNode) {
- // At each iteration, move all visitors from report to visitor list.
- for (BugReport::visitor_iterator I = R->visitor_begin(),
- E = R->visitor_end();
- I != E; ++I) {
- visitors.push_back(std::move(*I));
- }
+ // At each iteration, move all visitors from report to visitor list. This is
+ // important, because the Profile() functions of the visitors make sure that
+ // a visitor isn't added multiple times for the same node, but it's fine
+ // to add the a visitor with Profile() for different nodes (e.g. tracking
+ // a region at different points of the symbolic execution).
+ for (std::unique_ptr<BugReporterVisitor> &Visitor : R->visitors())
+ visitors.push_back(std::move(Visitor));
+
R->clearVisitors();
const ExplodedNode *Pred = NextNode->getFirstPred();
if (!Pred) {
- std::shared_ptr<PathDiagnosticPiece> LastPiece;
+ PathDiagnosticPieceRef LastPiece;
for (auto &V : visitors) {
V->finalizeVisitor(BRC, ErrorNode, *R);
if (auto Piece = V->getEndPath(BRC, ErrorNode, *R)) {
assert(!LastPiece &&
"There can only be one final piece in a diagnostic.");
+ assert(Piece->getKind() == PathDiagnosticPiece::Kind::Event &&
+ "The final piece must contain a message!");
LastPiece = std::move(Piece);
(*Notes)[ErrorNode].push_back(LastPiece);
}
@@ -2597,127 +2746,81 @@ generateVisitorsDiagnostics(BugReport *R, const ExplodedNode *ErrorNode,
return Notes;
}
-/// Find a non-invalidated report for a given equivalence class,
-/// and return together with a cache of visitors notes.
-/// If none found, return a nullptr paired with an empty cache.
-static
-std::pair<BugReport*, std::unique_ptr<VisitorsDiagnosticsTy>> findValidReport(
- TrimmedGraph &TrimG,
- ReportGraph &ErrorGraph,
- ArrayRef<BugReport *> &bugReports,
- AnalyzerOptions &Opts,
- GRBugReporter &Reporter) {
+Optional<PathDiagnosticBuilder> PathDiagnosticBuilder::findValidReport(
+ ArrayRef<PathSensitiveBugReport *> &bugReports,
+ PathSensitiveBugReporter &Reporter) {
- while (TrimG.popNextReportGraph(ErrorGraph)) {
+ BugPathGetter BugGraph(&Reporter.getGraph(), bugReports);
+
+ while (BugPathInfo *BugPath = BugGraph.getNextBugPath()) {
// Find the BugReport with the original location.
- assert(ErrorGraph.Index < bugReports.size());
- BugReport *R = bugReports[ErrorGraph.Index];
+ PathSensitiveBugReport *R = BugPath->Report;
assert(R && "No original report found for sliced graph.");
assert(R->isValid() && "Report selected by trimmed graph marked invalid.");
- const ExplodedNode *ErrorNode = ErrorGraph.ErrorNode;
+ const ExplodedNode *ErrorNode = BugPath->ErrorNode;
// Register refutation visitors first, if they mark the bug invalid no
// further analysis is required
- R->addVisitor(llvm::make_unique<LikelyFalsePositiveSuppressionBRVisitor>());
+ R->addVisitor(std::make_unique<LikelyFalsePositiveSuppressionBRVisitor>());
// Register additional node visitors.
- R->addVisitor(llvm::make_unique<NilReceiverBRVisitor>());
- R->addVisitor(llvm::make_unique<ConditionBRVisitor>());
- R->addVisitor(llvm::make_unique<TagVisitor>());
+ R->addVisitor(std::make_unique<NilReceiverBRVisitor>());
+ R->addVisitor(std::make_unique<ConditionBRVisitor>());
+ R->addVisitor(std::make_unique<TagVisitor>());
- BugReporterContext BRC(Reporter, ErrorGraph.BackMap);
+ BugReporterContext BRC(Reporter);
// Run all visitors on a given graph, once.
std::unique_ptr<VisitorsDiagnosticsTy> visitorNotes =
generateVisitorsDiagnostics(R, ErrorNode, BRC);
if (R->isValid()) {
- if (Opts.ShouldCrosscheckWithZ3) {
+ if (Reporter.getAnalyzerOptions().ShouldCrosscheckWithZ3) {
// If crosscheck is enabled, remove all visitors, add the refutation
// visitor and check again
R->clearVisitors();
- R->addVisitor(llvm::make_unique<FalsePositiveRefutationBRVisitor>());
+ R->addVisitor(std::make_unique<FalsePositiveRefutationBRVisitor>());
// We don't overrite the notes inserted by other visitors because the
// refutation manager does not add any new note to the path
- generateVisitorsDiagnostics(R, ErrorGraph.ErrorNode, BRC);
+ generateVisitorsDiagnostics(R, BugPath->ErrorNode, BRC);
}
// Check if the bug is still valid
if (R->isValid())
- return std::make_pair(R, std::move(visitorNotes));
+ return PathDiagnosticBuilder(
+ std::move(BRC), std::move(BugPath->BugPath), BugPath->Report,
+ BugPath->ErrorNode, std::move(visitorNotes));
}
}
- return std::make_pair(nullptr, llvm::make_unique<VisitorsDiagnosticsTy>());
+ return {};
}
std::unique_ptr<DiagnosticForConsumerMapTy>
-GRBugReporter::generatePathDiagnostics(
+PathSensitiveBugReporter::generatePathDiagnostics(
ArrayRef<PathDiagnosticConsumer *> consumers,
- ArrayRef<BugReport *> &bugReports) {
+ ArrayRef<PathSensitiveBugReport *> &bugReports) {
assert(!bugReports.empty());
- auto Out = llvm::make_unique<DiagnosticForConsumerMapTy>();
- bool HasValid = false;
- SmallVector<const ExplodedNode *, 32> errorNodes;
- for (const auto I : bugReports) {
- if (I->isValid()) {
- HasValid = true;
- errorNodes.push_back(I->getErrorNode());
- } else {
- // Keep the errorNodes list in sync with the bugReports list.
- errorNodes.push_back(nullptr);
- }
- }
-
- // If all the reports have been marked invalid by a previous path generation,
- // we're done.
- if (!HasValid)
- return Out;
+ auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
- TrimmedGraph TrimG(&getGraph(), errorNodes);
- ReportGraph ErrorGraph;
- auto ReportInfo = findValidReport(TrimG, ErrorGraph, bugReports,
- getAnalyzerOptions(), *this);
- BugReport *R = ReportInfo.first;
+ Optional<PathDiagnosticBuilder> PDB =
+ PathDiagnosticBuilder::findValidReport(bugReports, *this);
- if (R && R->isValid()) {
- const ExplodedNode *ErrorNode = ErrorGraph.ErrorNode;
+ if (PDB) {
for (PathDiagnosticConsumer *PC : consumers) {
- PathDiagnosticBuilder PDB(*this, R, ErrorGraph.BackMap, PC);
- std::unique_ptr<PathDiagnostic> PD = generatePathDiagnosticForConsumer(
- PC->getGenerationScheme(), PDB, ErrorNode, *ReportInfo.second);
- (*Out)[PC] = std::move(PD);
+ if (std::unique_ptr<PathDiagnostic> PD = PDB->generate(PC)) {
+ (*Out)[PC] = std::move(PD);
+ }
}
}
return Out;
}
-void BugReporter::Register(const BugType *BT) {
- BugTypes = F.add(BugTypes, BT);
-}
-
void BugReporter::emitReport(std::unique_ptr<BugReport> R) {
- if (const ExplodedNode *E = R->getErrorNode()) {
- // An error node must either be a sink or have a tag, otherwise
- // it could get reclaimed before the path diagnostic is created.
- assert((E->isSink() || E->getLocation().getTag()) &&
- "Error node must either be a sink or have a tag");
-
- const AnalysisDeclContext *DeclCtx =
- E->getLocationContext()->getAnalysisDeclContext();
- // The source of autosynthesized body can be handcrafted AST or a model
- // file. The locations from handcrafted ASTs have no valid source locations
- // and have to be discarded. Locations from model files should be preserved
- // for processing and reporting.
- if (DeclCtx->isBodyAutosynthesized() &&
- !DeclCtx->isBodyAutosynthesizedFromModelFile())
- return;
- }
-
- bool ValidSourceLoc = R->getLocation(getSourceManager()).isValid();
+ bool ValidSourceLoc = R->getLocation().isValid();
assert(ValidSourceLoc);
// If we mess up in a release build, we'd still prefer to just drop the bug
// instead of trying to go on.
@@ -2729,8 +2832,6 @@ void BugReporter::emitReport(std::unique_ptr<BugReport> R) {
R->Profile(ID);
// Lookup the equivance class. If there isn't one, create it.
- const BugType& BT = R->getBugType();
- Register(&BT);
void *InsertPos;
BugReportEquivClass* EQ = EQClasses.FindNodeOrInsertPos(ID, InsertPos);
@@ -2742,6 +2843,28 @@ void BugReporter::emitReport(std::unique_ptr<BugReport> R) {
EQ->AddReport(std::move(R));
}
+void PathSensitiveBugReporter::emitReport(std::unique_ptr<BugReport> R) {
+ if (auto PR = dyn_cast<PathSensitiveBugReport>(R.get()))
+ if (const ExplodedNode *E = PR->getErrorNode()) {
+ // An error node must either be a sink or have a tag, otherwise
+ // it could get reclaimed before the path diagnostic is created.
+ assert((E->isSink() || E->getLocation().getTag()) &&
+ "Error node must either be a sink or have a tag");
+
+ const AnalysisDeclContext *DeclCtx =
+ E->getLocationContext()->getAnalysisDeclContext();
+ // The source of autosynthesized body can be handcrafted AST or a model
+ // file. The locations from handcrafted ASTs have no valid source
+ // locations and have to be discarded. Locations from model files should
+ // be preserved for processing and reporting.
+ if (DeclCtx->isBodyAutosynthesized() &&
+ !DeclCtx->isBodyAutosynthesizedFromModelFile())
+ return;
+ }
+
+ BugReporter::emitReport(std::move(R));
+}
+
//===----------------------------------------------------------------------===//
// Emitting reports in equivalence classes.
//===----------------------------------------------------------------------===//
@@ -2758,107 +2881,19 @@ struct FRIEC_WLItem {
} // namespace
-static const CFGBlock *findBlockForNode(const ExplodedNode *N) {
- ProgramPoint P = N->getLocation();
- if (auto BEP = P.getAs<BlockEntrance>())
- return BEP->getBlock();
-
- // Find the node's current statement in the CFG.
- if (const Stmt *S = PathDiagnosticLocation::getStmt(N))
- return N->getLocationContext()->getAnalysisDeclContext()
- ->getCFGStmtMap()->getBlock(S);
-
- return nullptr;
-}
-
-// Returns true if by simply looking at the block, we can be sure that it
-// results in a sink during analysis. This is useful to know when the analysis
-// was interrupted, and we try to figure out if it would sink eventually.
-// There may be many more reasons why a sink would appear during analysis
-// (eg. checkers may generate sinks arbitrarily), but here we only consider
-// sinks that would be obvious by looking at the CFG.
-static bool isImmediateSinkBlock(const CFGBlock *Blk) {
- if (Blk->hasNoReturnElement())
- return true;
-
- // FIXME: Throw-expressions are currently generating sinks during analysis:
- // they're not supported yet, and also often used for actually terminating
- // the program. So we should treat them as sinks in this analysis as well,
- // at least for now, but once we have better support for exceptions,
- // we'd need to carefully handle the case when the throw is being
- // immediately caught.
- if (std::any_of(Blk->begin(), Blk->end(), [](const CFGElement &Elm) {
- if (Optional<CFGStmt> StmtElm = Elm.getAs<CFGStmt>())
- if (isa<CXXThrowExpr>(StmtElm->getStmt()))
- return true;
- return false;
- }))
- return true;
-
- return false;
-}
-
-// Returns true if by looking at the CFG surrounding the node's program
-// point, we can be sure that any analysis starting from this point would
-// eventually end with a sink. We scan the child CFG blocks in a depth-first
-// manner and see if all paths eventually end up in an immediate sink block.
-static bool isInevitablySinking(const ExplodedNode *N) {
- const CFG &Cfg = N->getCFG();
-
- const CFGBlock *StartBlk = findBlockForNode(N);
- if (!StartBlk)
- return false;
- if (isImmediateSinkBlock(StartBlk))
- return true;
-
- llvm::SmallVector<const CFGBlock *, 32> DFSWorkList;
- llvm::SmallPtrSet<const CFGBlock *, 32> Visited;
-
- DFSWorkList.push_back(StartBlk);
- while (!DFSWorkList.empty()) {
- const CFGBlock *Blk = DFSWorkList.back();
- DFSWorkList.pop_back();
- Visited.insert(Blk);
-
- // If at least one path reaches the CFG exit, it means that control is
- // returned to the caller. For now, say that we are not sure what
- // happens next. If necessary, this can be improved to analyze
- // the parent StackFrameContext's call site in a similar manner.
- if (Blk == &Cfg.getExit())
- return false;
-
- for (const auto &Succ : Blk->succs()) {
- if (const CFGBlock *SuccBlk = Succ.getReachableBlock()) {
- if (!isImmediateSinkBlock(SuccBlk) && !Visited.count(SuccBlk)) {
- // If the block has reachable child blocks that aren't no-return,
- // add them to the worklist.
- DFSWorkList.push_back(SuccBlk);
- }
- }
- }
- }
-
- // Nothing reached the exit. It can only mean one thing: there's no return.
- return true;
-}
-
-static BugReport *
-FindReportInEquivalenceClass(BugReportEquivClass& EQ,
- SmallVectorImpl<BugReport*> &bugReports) {
- BugReportEquivClass::iterator I = EQ.begin(), E = EQ.end();
- assert(I != E);
- const BugType& BT = I->getBugType();
-
+BugReport *PathSensitiveBugReporter::findReportInEquivalenceClass(
+ BugReportEquivClass &EQ, SmallVectorImpl<BugReport *> &bugReports) {
// 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.
+ assert(EQ.getReports().size() > 0);
+ const BugType& BT = EQ.getReports()[0]->getBugType();
if (!BT.isSuppressOnSink()) {
- BugReport *R = &*I;
- for (auto &I : EQ) {
- const ExplodedNode *N = I.getErrorNode();
- if (N) {
- R = &I;
- bugReports.push_back(R);
+ BugReport *R = EQ.getReports()[0].get();
+ for (auto &J : EQ.getReports()) {
+ if (auto *PR = dyn_cast<PathSensitiveBugReport>(J.get())) {
+ R = PR;
+ bugReports.push_back(PR);
}
}
return R;
@@ -2872,20 +2907,21 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
// stack for very long paths.
BugReport *exampleReport = nullptr;
- for (; I != E; ++I) {
- const ExplodedNode *errorNode = I->getErrorNode();
-
- if (!errorNode)
+ for (const auto &I: EQ.getReports()) {
+ auto *R = dyn_cast<PathSensitiveBugReport>(I.get());
+ if (!R)
continue;
+
+ const ExplodedNode *errorNode = R->getErrorNode();
if (errorNode->isSink()) {
llvm_unreachable(
"BugType::isSuppressSink() should not be 'true' for sink end nodes");
}
// No successors? By definition this nodes isn't post-dominated by a sink.
if (errorNode->succ_empty()) {
- bugReports.push_back(&*I);
+ bugReports.push_back(R);
if (!exampleReport)
- exampleReport = &*I;
+ exampleReport = R;
continue;
}
@@ -2893,8 +2929,9 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
// to being post-dominated by a sink. This works better when the analysis
// is incomplete and we have never reached the no-return function call(s)
// that we'd inevitably bump into on this path.
- if (isInevitablySinking(errorNode))
- continue;
+ if (const CFGBlock *ErrorB = errorNode->getCFGBlock())
+ if (ErrorB->isInevitablySinking())
+ continue;
// At this point we know that 'N' is not a sink and it has at least one
// successor. Use a DFS worklist to find a non-sink end-of-path node.
@@ -2917,9 +2954,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(&*I);
+ bugReports.push_back(R);
if (!exampleReport)
- exampleReport = &*I;
+ exampleReport = R;
WL.clear();
break;
}
@@ -2950,7 +2987,7 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
void BugReporter::FlushReport(BugReportEquivClass& EQ) {
SmallVector<BugReport*, 10> bugReports;
- BugReport *report = FindReportInEquivalenceClass(EQ, bugReports);
+ BugReport *report = findReportInEquivalenceClass(EQ, bugReports);
if (!report)
return;
@@ -2965,8 +3002,8 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
// If the path is empty, generate a single step path with the location
// of the issue.
if (PD->path.empty()) {
- PathDiagnosticLocation L = report->getLocation(getSourceManager());
- auto piece = llvm::make_unique<PathDiagnosticEventPiece>(
+ PathDiagnosticLocation L = report->getLocation();
+ auto piece = std::make_unique<PathDiagnosticEventPiece>(
L, report->getDescription());
for (SourceRange Range : report->getRanges())
piece->addRange(Range);
@@ -2993,10 +3030,8 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
Pieces.push_front(*I);
}
- // Get the meta data.
- const BugReport::ExtraTextList &Meta = report->getExtraText();
- for (const auto &i : Meta)
- PD->addMeta(i);
+ for (const auto &I : report->getFixits())
+ Pieces.back()->addFixit(I);
updateExecutedLinesWithDiagnosticPieces(*PD);
Consumer->HandlePathDiagnostic(std::move(PD));
@@ -3006,7 +3041,7 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
/// Insert all lines participating in the function signature \p Signature
/// into \p ExecutedLines.
static void populateExecutedLinesWithFunctionSignature(
- const Decl *Signature, SourceManager &SM,
+ const Decl *Signature, const SourceManager &SM,
FilesToLineNumsMap &ExecutedLines) {
SourceRange SignatureSourceRange;
const Stmt* Body = Signature->getBody();
@@ -3031,7 +3066,7 @@ static void populateExecutedLinesWithFunctionSignature(
}
static void populateExecutedLinesWithStmt(
- const Stmt *S, SourceManager &SM,
+ const Stmt *S, const SourceManager &SM,
FilesToLineNumsMap &ExecutedLines) {
SourceLocation Loc = S->getSourceRange().getBegin();
if (!Loc.isValid())
@@ -3045,8 +3080,8 @@ static void populateExecutedLinesWithStmt(
/// \return all executed lines including function signatures on the path
/// starting from \p N.
static std::unique_ptr<FilesToLineNumsMap>
-findExecutedLines(SourceManager &SM, const ExplodedNode *N) {
- auto ExecutedLines = llvm::make_unique<FilesToLineNumsMap>();
+findExecutedLines(const SourceManager &SM, const ExplodedNode *N) {
+ auto ExecutedLines = std::make_unique<FilesToLineNumsMap>();
while (N) {
if (N->getFirstPred() == nullptr) {
@@ -3057,7 +3092,7 @@ findExecutedLines(SourceManager &SM, const ExplodedNode *N) {
// Inlined function: show signature.
const Decl* D = CE->getCalleeContext()->getDecl();
populateExecutedLinesWithFunctionSignature(D, SM, *ExecutedLines);
- } else if (const Stmt *S = PathDiagnosticLocation::getStmt(N)) {
+ } else if (const Stmt *S = N->getStmtForDiagnostics()) {
populateExecutedLinesWithStmt(S, SM, *ExecutedLines);
// Show extra context for some parent kinds.
@@ -3082,16 +3117,89 @@ findExecutedLines(SourceManager &SM, const ExplodedNode *N) {
std::unique_ptr<DiagnosticForConsumerMapTy>
BugReporter::generateDiagnosticForConsumerMap(
- BugReport *report, ArrayRef<PathDiagnosticConsumer *> consumers,
+ BugReport *exampleReport, ArrayRef<PathDiagnosticConsumer *> consumers,
ArrayRef<BugReport *> bugReports) {
+ auto *basicReport = cast<BasicBugReport>(exampleReport);
+ auto Out = std::make_unique<DiagnosticForConsumerMapTy>();
+ for (auto *Consumer : consumers)
+ (*Out)[Consumer] = generateDiagnosticForBasicReport(basicReport);
+ return Out;
+}
- if (!report->isPathSensitive()) {
- auto Out = llvm::make_unique<DiagnosticForConsumerMapTy>();
- for (auto *Consumer : consumers)
- (*Out)[Consumer] = generateEmptyDiagnosticForReport(report,
- getSourceManager());
- return Out;
+static PathDiagnosticCallPiece *
+getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP,
+ const SourceManager &SMgr) {
+ SourceLocation CallLoc = CP->callEnter.asLocation();
+
+ // If the call is within a macro, don't do anything (for now).
+ if (CallLoc.isMacroID())
+ return nullptr;
+
+ assert(AnalysisManager::isInCodeFile(CallLoc, SMgr) &&
+ "The call piece should not be in a header file.");
+
+ // Check if CP represents a path through a function outside of the main file.
+ if (!AnalysisManager::isInCodeFile(CP->callEnterWithin.asLocation(), SMgr))
+ return CP;
+
+ const PathPieces &Path = CP->path;
+ if (Path.empty())
+ return nullptr;
+
+ // Check if the last piece in the callee path is a call to a function outside
+ // of the main file.
+ if (auto *CPInner = dyn_cast<PathDiagnosticCallPiece>(Path.back().get()))
+ return getFirstStackedCallToHeaderFile(CPInner, SMgr);
+
+ // Otherwise, the last piece is in the main file.
+ return nullptr;
+}
+
+static void resetDiagnosticLocationToMainFile(PathDiagnostic &PD) {
+ if (PD.path.empty())
+ return;
+
+ PathDiagnosticPiece *LastP = PD.path.back().get();
+ assert(LastP);
+ const SourceManager &SMgr = LastP->getLocation().getManager();
+
+ // We only need to check if the report ends inside headers, if the last piece
+ // is a call piece.
+ if (auto *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) {
+ CP = getFirstStackedCallToHeaderFile(CP, SMgr);
+ if (CP) {
+ // Mark the piece.
+ CP->setAsLastInMainSourceFile();
+
+ // Update the path diagnostic message.
+ const auto *ND = dyn_cast<NamedDecl>(CP->getCallee());
+ if (ND) {
+ SmallString<200> buf;
+ llvm::raw_svector_ostream os(buf);
+ os << " (within a call to '" << ND->getDeclName() << "')";
+ PD.appendToDesc(os.str());
+ }
+
+ // Reset the report containing declaration and location.
+ PD.setDeclWithIssue(CP->getCaller());
+ PD.setLocation(CP->getLocation());
+
+ return;
+ }
}
+}
+
+
+
+std::unique_ptr<DiagnosticForConsumerMapTy>
+PathSensitiveBugReporter::generateDiagnosticForConsumerMap(
+ BugReport *exampleReport, ArrayRef<PathDiagnosticConsumer *> consumers,
+ ArrayRef<BugReport *> bugReports) {
+ std::vector<BasicBugReport *> BasicBugReports;
+ std::vector<PathSensitiveBugReport *> PathSensitiveBugReports;
+ if (isa<BasicBugReport>(exampleReport))
+ return BugReporter::generateDiagnosticForConsumerMap(exampleReport,
+ consumers, bugReports);
// Generate the full path sensitive diagnostic, using the generation scheme
// specified by the PathDiagnosticConsumer. Note that we have to generate
@@ -3099,8 +3207,13 @@ BugReporter::generateDiagnosticForConsumerMap(
// the BugReporterVisitors may mark this bug as a false positive.
assert(!bugReports.empty());
MaxBugClassSize.updateMax(bugReports.size());
- std::unique_ptr<DiagnosticForConsumerMapTy> Out =
- generatePathDiagnostics(consumers, bugReports);
+
+ // Avoid copying the whole array because there may be a lot of reports.
+ ArrayRef<PathSensitiveBugReport *> convertedArrayOfReports(
+ reinterpret_cast<PathSensitiveBugReport *const *>(&*bugReports.begin()),
+ reinterpret_cast<PathSensitiveBugReport *const *>(&*bugReports.end()));
+ std::unique_ptr<DiagnosticForConsumerMapTy> Out = generatePathDiagnostics(
+ consumers, convertedArrayOfReports);
if (Out->empty())
return Out;
@@ -3109,40 +3222,43 @@ BugReporter::generateDiagnosticForConsumerMap(
// Examine the report and see if the last piece is in a header. Reset the
// report location to the last piece in the main source file.
- AnalyzerOptions &Opts = getAnalyzerOptions();
+ const AnalyzerOptions &Opts = getAnalyzerOptions();
for (auto const &P : *Out)
if (Opts.ShouldReportIssuesInMainSourceFile && !Opts.AnalyzeAll)
- P.second->resetDiagnosticLocationToMainFile();
+ resetDiagnosticLocationToMainFile(*P.second);
return Out;
}
void BugReporter::EmitBasicReport(const Decl *DeclWithIssue,
- const CheckerBase *Checker,
- StringRef Name, StringRef Category,
- StringRef Str, PathDiagnosticLocation Loc,
- ArrayRef<SourceRange> Ranges) {
- EmitBasicReport(DeclWithIssue, Checker->getCheckName(), Name, Category, Str,
- Loc, Ranges);
+ const CheckerBase *Checker, StringRef Name,
+ StringRef Category, StringRef Str,
+ PathDiagnosticLocation Loc,
+ ArrayRef<SourceRange> Ranges,
+ ArrayRef<FixItHint> Fixits) {
+ EmitBasicReport(DeclWithIssue, Checker->getCheckerName(), Name, Category, Str,
+ Loc, Ranges, Fixits);
}
void BugReporter::EmitBasicReport(const Decl *DeclWithIssue,
- CheckName CheckName,
+ CheckerNameRef CheckName,
StringRef name, StringRef category,
StringRef str, PathDiagnosticLocation Loc,
- ArrayRef<SourceRange> Ranges) {
+ ArrayRef<SourceRange> Ranges,
+ ArrayRef<FixItHint> Fixits) {
// 'BT' is owned by BugReporter.
BugType *BT = getBugTypeForName(CheckName, name, category);
- auto R = llvm::make_unique<BugReport>(*BT, str, Loc);
+ auto R = std::make_unique<BasicBugReport>(*BT, str, Loc);
R->setDeclWithIssue(DeclWithIssue);
- for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
- I != E; ++I)
- R->addRange(*I);
+ for (const auto &SR : Ranges)
+ R->addRange(SR);
+ for (const auto &FH : Fixits)
+ R->addFixItHint(FH);
emitReport(std::move(R));
}
-BugType *BugReporter::getBugTypeForName(CheckName CheckName, StringRef name,
- StringRef category) {
+BugType *BugReporter::getBugTypeForName(CheckerNameRef CheckName,
+ StringRef name, StringRef category) {
SmallString<136> fullDesc;
llvm::raw_svector_ostream(fullDesc) << CheckName.getName() << ":" << name
<< ":" << category;
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 250793c4baff..7ba93b858baf 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -26,6 +26,7 @@
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
@@ -34,7 +35,6 @@
#include "clang/Lex/Lexer.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
@@ -180,21 +180,60 @@ static bool hasVisibleUpdate(const ExplodedNode *LeftNode, SVal LeftVal,
RLCV->getStore() == RightNode->getState()->getStore();
}
-static Optional<const llvm::APSInt *>
-getConcreteIntegerValue(const Expr *CondVarExpr, const ExplodedNode *N) {
+static Optional<SVal> getSValForVar(const Expr *CondVarExpr,
+ const ExplodedNode *N) {
ProgramStateRef State = N->getState();
const LocationContext *LCtx = N->getLocationContext();
+ assert(CondVarExpr);
+ CondVarExpr = CondVarExpr->IgnoreImpCasts();
+
// The declaration of the value may rely on a pointer so take its l-value.
- if (const auto *DRE = dyn_cast_or_null<DeclRefExpr>(CondVarExpr)) {
- if (const auto *VD = dyn_cast_or_null<VarDecl>(DRE->getDecl())) {
- SVal DeclSVal = State->getSVal(State->getLValue(VD, LCtx));
- if (auto DeclCI = DeclSVal.getAs<nonloc::ConcreteInt>())
- return &DeclCI->getValue();
- }
- }
+ // FIXME: As seen in VisitCommonDeclRefExpr, sometimes DeclRefExpr may
+ // evaluate to a FieldRegion when it refers to a declaration of a lambda
+ // capture variable. We most likely need to duplicate that logic here.
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(CondVarExpr))
+ if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+ return State->getSVal(State->getLValue(VD, LCtx));
+
+ if (const auto *ME = dyn_cast<MemberExpr>(CondVarExpr))
+ if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ if (auto FieldL = State->getSVal(ME, LCtx).getAs<Loc>())
+ return State->getRawSVal(*FieldL, FD->getType());
+
+ return None;
+}
+
+static Optional<const llvm::APSInt *>
+getConcreteIntegerValue(const Expr *CondVarExpr, const ExplodedNode *N) {
- return {};
+ if (Optional<SVal> V = getSValForVar(CondVarExpr, N))
+ if (auto CI = V->getAs<nonloc::ConcreteInt>())
+ return &CI->getValue();
+ return None;
+}
+
+static bool isVarAnInterestingCondition(const Expr *CondVarExpr,
+ const ExplodedNode *N,
+ const PathSensitiveBugReport *B) {
+ // Even if this condition is marked as interesting, it isn't *that*
+ // interesting if it didn't happen in a nested stackframe, the user could just
+ // follow the arrows.
+ if (!B->getErrorNode()->getStackFrame()->isParentOf(N->getStackFrame()))
+ return false;
+
+ if (Optional<SVal> V = getSValForVar(CondVarExpr, N))
+ if (Optional<bugreporter::TrackingKind> K = B->getInterestingnessKind(*V))
+ return *K == bugreporter::TrackingKind::Condition;
+
+ return false;
+}
+
+static bool isInterestingExpr(const Expr *E, const ExplodedNode *N,
+ const PathSensitiveBugReport *B) {
+ if (Optional<SVal> V = getSValForVar(E, N))
+ return B->getInterestingnessKind(*V).hasValue();
+ return false;
}
/// \return name of the macro inside the location \p Loc.
@@ -255,21 +294,21 @@ static bool wasRegionOfInterestModifiedAt(const SubRegion *RegionOfInterest,
// Implementation of BugReporterVisitor.
//===----------------------------------------------------------------------===//
-std::shared_ptr<PathDiagnosticPiece>
-BugReporterVisitor::getEndPath(BugReporterContext &,
- const ExplodedNode *, BugReport &) {
+PathDiagnosticPieceRef BugReporterVisitor::getEndPath(BugReporterContext &,
+ const ExplodedNode *,
+ PathSensitiveBugReport &) {
return nullptr;
}
-void
-BugReporterVisitor::finalizeVisitor(BugReporterContext &,
- const ExplodedNode *, BugReport &) {}
-
-std::shared_ptr<PathDiagnosticPiece> BugReporterVisitor::getDefaultEndPath(
- BugReporterContext &BRC, const ExplodedNode *EndPathNode, BugReport &BR) {
- PathDiagnosticLocation L =
- PathDiagnosticLocation::createEndOfPath(EndPathNode,BRC.getSourceManager());
+void BugReporterVisitor::finalizeVisitor(BugReporterContext &,
+ const ExplodedNode *,
+ PathSensitiveBugReport &) {}
+PathDiagnosticPieceRef
+BugReporterVisitor::getDefaultEndPath(const BugReporterContext &BRC,
+ const ExplodedNode *EndPathNode,
+ const PathSensitiveBugReport &BR) {
+ PathDiagnosticLocation L = BR.getLocation();
const auto &Ranges = BR.getRanges();
// Only add the statement itself as a range if we didn't specify any
@@ -297,6 +336,7 @@ class NoStoreFuncVisitor final : public BugReporterVisitor {
MemRegionManager &MmrMgr;
const SourceManager &SM;
const PrintingPolicy &PP;
+ bugreporter::TrackingKind TKind;
/// Recursion limit for dereferencing fields when looking for the
/// region of interest.
@@ -317,10 +357,10 @@ class NoStoreFuncVisitor final : public BugReporterVisitor {
using RegionVector = SmallVector<const MemRegion *, 5>;
public:
- NoStoreFuncVisitor(const SubRegion *R)
+ NoStoreFuncVisitor(const SubRegion *R, bugreporter::TrackingKind TKind)
: RegionOfInterest(R), MmrMgr(*R->getMemRegionManager()),
SM(MmrMgr.getContext().getSourceManager()),
- PP(MmrMgr.getContext().getPrintingPolicy()) {}
+ PP(MmrMgr.getContext().getPrintingPolicy()), TKind(TKind) {}
void Profile(llvm::FoldingSetNodeID &ID) const override {
static int Tag = 0;
@@ -333,9 +373,9 @@ public:
return static_cast<void *>(&Tag);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BR,
- BugReport &R) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BR,
+ PathSensitiveBugReport &R) override;
private:
/// Attempts to find the region of interest in a given record decl,
@@ -368,11 +408,11 @@ private:
/// either emit a note or suppress the report enirely.
/// \return Diagnostics piece for region not modified in the current function,
/// if it decides to emit one.
- std::shared_ptr<PathDiagnosticPiece>
- maybeEmitNote(BugReport &R, const CallEvent &Call, const ExplodedNode *N,
- const RegionVector &FieldChain, const MemRegion *MatchedRegion,
- StringRef FirstElement, bool FirstIsReferenceType,
- unsigned IndirectionLevel);
+ PathDiagnosticPieceRef
+ maybeEmitNote(PathSensitiveBugReport &R, const CallEvent &Call,
+ const ExplodedNode *N, const RegionVector &FieldChain,
+ const MemRegion *MatchedRegion, StringRef FirstElement,
+ bool FirstIsReferenceType, unsigned IndirectionLevel);
/// Pretty-print region \p MatchedRegion to \p os.
/// \return Whether printing succeeded.
@@ -501,9 +541,9 @@ NoStoreFuncVisitor::findRegionOfInterestInRecord(
return None;
}
-std::shared_ptr<PathDiagnosticPiece>
+PathDiagnosticPieceRef
NoStoreFuncVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BR,
- BugReport &R) {
+ PathSensitiveBugReport &R) {
const LocationContext *Ctx = N->getLocationContext();
const StackFrameContext *SCtx = Ctx->getStackFrame();
@@ -611,8 +651,11 @@ void NoStoreFuncVisitor::findModifyingFrames(const ExplodedNode *N) {
} while (N);
}
-std::shared_ptr<PathDiagnosticPiece> NoStoreFuncVisitor::maybeEmitNote(
- BugReport &R, const CallEvent &Call, const ExplodedNode *N,
+static llvm::StringLiteral WillBeUsedForACondition =
+ ", which participates in a condition later";
+
+PathDiagnosticPieceRef NoStoreFuncVisitor::maybeEmitNote(
+ PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N,
const RegionVector &FieldChain, const MemRegion *MatchedRegion,
StringRef FirstElement, bool FirstIsReferenceType,
unsigned IndirectionLevel) {
@@ -657,6 +700,8 @@ std::shared_ptr<PathDiagnosticPiece> NoStoreFuncVisitor::maybeEmitNote(
return nullptr;
os << "'";
+ if (TKind == bugreporter::TrackingKind::Condition)
+ os << WillBeUsedForACondition;
return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
}
@@ -752,13 +797,12 @@ class MacroNullReturnSuppressionVisitor final : public BugReporterVisitor {
bool WasModified = false;
public:
- MacroNullReturnSuppressionVisitor(const SubRegion *R,
- const SVal V) : RegionOfInterest(R),
- ValueAtDereference(V) {}
+ MacroNullReturnSuppressionVisitor(const SubRegion *R, const SVal V)
+ : RegionOfInterest(R), ValueAtDereference(V) {}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override {
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override {
if (WasModified)
return nullptr;
@@ -784,12 +828,12 @@ public:
static void addMacroVisitorIfNecessary(
const ExplodedNode *N, const MemRegion *R,
- bool EnableNullFPSuppression, BugReport &BR,
+ bool EnableNullFPSuppression, PathSensitiveBugReport &BR,
const SVal V) {
AnalyzerOptions &Options = N->getState()->getAnalysisManager().options;
if (EnableNullFPSuppression &&
Options.ShouldSuppressNullReturnPaths && V.getAs<Loc>())
- BR.addVisitor(llvm::make_unique<MacroNullReturnSuppressionVisitor>(
+ BR.addVisitor(std::make_unique<MacroNullReturnSuppressionVisitor>(
R->getAs<SubRegion>(), V));
}
@@ -806,7 +850,7 @@ private:
/// \return Source location of right hand side of an assignment
/// into \c RegionOfInterest, empty optional if none found.
Optional<SourceLocation> matchAssignment(const ExplodedNode *N) {
- const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ const Stmt *S = N->getStmtForDiagnostics();
ProgramStateRef State = N->getState();
auto *LCtx = N->getLocationContext();
if (!S)
@@ -841,7 +885,7 @@ namespace {
/// This visitor is intended to be used when another visitor discovers that an
/// interesting value comes from an inlined function call.
class ReturnVisitor : public BugReporterVisitor {
- const StackFrameContext *StackFrame;
+ const StackFrameContext *CalleeSFC;
enum {
Initial,
MaybeUnsuppress,
@@ -851,13 +895,13 @@ class ReturnVisitor : public BugReporterVisitor {
bool EnableNullFPSuppression;
bool ShouldInvalidate = true;
AnalyzerOptions& Options;
+ bugreporter::TrackingKind TKind;
public:
- ReturnVisitor(const StackFrameContext *Frame,
- bool Suppressed,
- AnalyzerOptions &Options)
- : StackFrame(Frame), EnableNullFPSuppression(Suppressed),
- Options(Options) {}
+ ReturnVisitor(const StackFrameContext *Frame, bool Suppressed,
+ AnalyzerOptions &Options, bugreporter::TrackingKind TKind)
+ : CalleeSFC(Frame), EnableNullFPSuppression(Suppressed),
+ Options(Options), TKind(TKind) {}
static void *getTag() {
static int Tag = 0;
@@ -866,7 +910,7 @@ public:
void Profile(llvm::FoldingSetNodeID &ID) const override {
ID.AddPointer(ReturnVisitor::getTag());
- ID.AddPointer(StackFrame);
+ ID.AddPointer(CalleeSFC);
ID.AddBoolean(EnableNullFPSuppression);
}
@@ -878,8 +922,9 @@ public:
/// the statement is a call that was inlined, we add the visitor to the
/// bug report, so it can print a note later.
static void addVisitorIfNecessary(const ExplodedNode *Node, const Stmt *S,
- BugReport &BR,
- bool InEnableNullFPSuppression) {
+ PathSensitiveBugReport &BR,
+ bool InEnableNullFPSuppression,
+ bugreporter::TrackingKind TKind) {
if (!CallEvent::isCallStmt(S))
return;
@@ -950,17 +995,16 @@ public:
if (Optional<Loc> RetLoc = RetVal.getAs<Loc>())
EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
- BR.markInteresting(CalleeContext);
- BR.addVisitor(llvm::make_unique<ReturnVisitor>(CalleeContext,
+ BR.addVisitor(std::make_unique<ReturnVisitor>(CalleeContext,
EnableNullFPSuppression,
- Options));
+ Options, TKind));
}
- std::shared_ptr<PathDiagnosticPiece>
- visitNodeInitial(const ExplodedNode *N,
- BugReporterContext &BRC, BugReport &BR) {
+ PathDiagnosticPieceRef visitNodeInitial(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
// Only print a message at the interesting return statement.
- if (N->getLocationContext() != StackFrame)
+ if (N->getLocationContext() != CalleeSFC)
return nullptr;
Optional<StmtPoint> SP = N->getLocationAs<StmtPoint>();
@@ -974,7 +1018,7 @@ public:
// Okay, we're at the right return statement, but do we have the return
// value available?
ProgramStateRef State = N->getState();
- SVal V = State->getSVal(Ret, StackFrame);
+ SVal V = State->getSVal(Ret, CalleeSFC);
if (V.isUnknownOrUndef())
return nullptr;
@@ -1001,13 +1045,16 @@ public:
RetE = RetE->IgnoreParenCasts();
- // If we're returning 0, we should track where that 0 came from.
- bugreporter::trackExpressionValue(N, RetE, BR, EnableNullFPSuppression);
+ // Let's track the return value.
+ bugreporter::trackExpressionValue(
+ N, RetE, BR, TKind, EnableNullFPSuppression);
// Build an appropriate message based on the return value.
SmallString<64> Msg;
llvm::raw_svector_ostream Out(Msg);
+ bool WouldEventBeMeaningless = false;
+
if (State->isNull(V).isConstrainedTrue()) {
if (V.getAs<Loc>()) {
@@ -1030,10 +1077,19 @@ public:
} else {
if (auto CI = V.getAs<nonloc::ConcreteInt>()) {
Out << "Returning the value " << CI->getValue();
- } else if (V.getAs<Loc>()) {
- Out << "Returning pointer";
} else {
- Out << "Returning value";
+ // There is nothing interesting about returning a value, when it is
+ // plain value without any constraints, and the function is guaranteed
+ // to return that every time. We could use CFG::isLinear() here, but
+ // constexpr branches are obvious to the compiler, not necesserily to
+ // the programmer.
+ if (N->getCFG().size() == 3)
+ WouldEventBeMeaningless = true;
+
+ if (V.getAs<Loc>())
+ Out << "Returning pointer";
+ else
+ Out << "Returning value";
}
}
@@ -1052,26 +1108,36 @@ public:
Out << " (loaded from '" << *DD << "')";
}
- PathDiagnosticLocation L(Ret, BRC.getSourceManager(), StackFrame);
+ PathDiagnosticLocation L(Ret, BRC.getSourceManager(), CalleeSFC);
if (!L.isValid() || !L.asLocation().isValid())
return nullptr;
- return std::make_shared<PathDiagnosticEventPiece>(L, Out.str());
+ if (TKind == bugreporter::TrackingKind::Condition)
+ Out << WillBeUsedForACondition;
+
+ auto EventPiece = std::make_shared<PathDiagnosticEventPiece>(L, Out.str());
+
+ // If we determined that the note is meaningless, make it prunable, and
+ // don't mark the stackframe interesting.
+ if (WouldEventBeMeaningless)
+ EventPiece->setPrunable(true);
+ else
+ BR.markInteresting(CalleeSFC);
+
+ return EventPiece;
}
- std::shared_ptr<PathDiagnosticPiece>
- visitNodeMaybeUnsuppress(const ExplodedNode *N,
- BugReporterContext &BRC, BugReport &BR) {
-#ifndef NDEBUG
+ PathDiagnosticPieceRef visitNodeMaybeUnsuppress(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
assert(Options.ShouldAvoidSuppressingNullArgumentPaths);
-#endif
// Are we at the entry node for this call?
Optional<CallEnter> CE = N->getLocationAs<CallEnter>();
if (!CE)
return nullptr;
- if (CE->getCalleeContext() != StackFrame)
+ if (CE->getCalleeContext() != CalleeSFC)
return nullptr;
Mode = Satisfied;
@@ -1083,7 +1149,7 @@ public:
CallEventManager &CallMgr = StateMgr.getCallEventManager();
ProgramStateRef State = N->getState();
- CallEventRef<> Call = CallMgr.getCaller(StackFrame, State);
+ CallEventRef<> Call = CallMgr.getCaller(CalleeSFC, State);
for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) {
Optional<Loc> ArgV = Call->getArgSVal(I).getAs<Loc>();
if (!ArgV)
@@ -1097,7 +1163,7 @@ public:
if (!State->isNull(*ArgV).isConstrainedTrue())
continue;
- if (bugreporter::trackExpressionValue(N, ArgE, BR, EnableNullFPSuppression))
+ if (trackExpressionValue(N, ArgE, BR, TKind, EnableNullFPSuppression))
ShouldInvalidate = false;
// If we /can't/ track the null pointer, we should err on the side of
@@ -1108,9 +1174,9 @@ public:
return nullptr;
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override {
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override {
switch (Mode) {
case Initial:
return visitNodeInitial(N, BRC, BR);
@@ -1124,9 +1190,9 @@ public:
}
void finalizeVisitor(BugReporterContext &, const ExplodedNode *,
- BugReport &BR) override {
+ PathSensitiveBugReport &BR) override {
if (EnableNullFPSuppression && ShouldInvalidate)
- BR.markInvalid(ReturnVisitor::getTag(), StackFrame);
+ BR.markInvalid(ReturnVisitor::getTag(), CalleeSFC);
}
};
@@ -1141,6 +1207,7 @@ void FindLastStoreBRVisitor::Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(&tag);
ID.AddPointer(R);
ID.Add(V);
+ ID.AddInteger(static_cast<int>(TKind));
ID.AddBoolean(EnableNullFPSuppression);
}
@@ -1246,9 +1313,8 @@ static void showBRParamDiagnostics(llvm::raw_svector_ostream& os,
}
/// Show default diagnostics for storing bad region.
-static void showBRDefaultDiagnostics(llvm::raw_svector_ostream& os,
- const MemRegion *R,
- SVal V) {
+static void showBRDefaultDiagnostics(llvm::raw_svector_ostream &os,
+ const MemRegion *R, SVal V) {
if (V.getAs<loc::ConcreteInt>()) {
bool b = false;
if (R->isBoundable()) {
@@ -1291,9 +1357,10 @@ static void showBRDefaultDiagnostics(llvm::raw_svector_ostream& os,
}
}
-std::shared_ptr<PathDiagnosticPiece>
+PathDiagnosticPieceRef
FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
- BugReporterContext &BRC, BugReport &BR) {
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
if (Satisfied)
return nullptr;
@@ -1314,7 +1381,7 @@ FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
// should track the initializer expression.
if (Optional<PostInitializer> PIP = Pred->getLocationAs<PostInitializer>()) {
const MemRegion *FieldReg = (const MemRegion *)PIP->getLocationValue();
- if (FieldReg && FieldReg == R) {
+ if (FieldReg == R) {
StoreSite = Pred;
InitE = PIP->getInitializer()->getInit();
}
@@ -1351,14 +1418,19 @@ FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
if (Optional<CallEnter> CE = Succ->getLocationAs<CallEnter>()) {
if (const auto *VR = dyn_cast<VarRegion>(R)) {
- const auto *Param = cast<ParmVarDecl>(VR->getDecl());
+ if (const auto *Param = dyn_cast<ParmVarDecl>(VR->getDecl())) {
+ ProgramStateManager &StateMgr = BRC.getStateManager();
+ CallEventManager &CallMgr = StateMgr.getCallEventManager();
- ProgramStateManager &StateMgr = BRC.getStateManager();
- CallEventManager &CallMgr = StateMgr.getCallEventManager();
-
- CallEventRef<> Call = CallMgr.getCaller(CE->getCalleeContext(),
- Succ->getState());
- InitE = Call->getArgExpr(Param->getFunctionScopeIndex());
+ CallEventRef<> Call = CallMgr.getCaller(CE->getCalleeContext(),
+ Succ->getState());
+ InitE = Call->getArgExpr(Param->getFunctionScopeIndex());
+ } else {
+ // Handle Objective-C 'self'.
+ assert(isa<ImplicitParamDecl>(VR->getDecl()));
+ InitE = cast<ObjCMessageExpr>(CE->getCalleeContext()->getCallSite())
+ ->getInstanceReceiver()->IgnoreParenCasts();
+ }
IsParam = true;
}
}
@@ -1371,22 +1443,23 @@ FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
if (!StoreSite)
return nullptr;
+
Satisfied = true;
// If we have an expression that provided the value, try to track where it
// came from.
if (InitE) {
- if (V.isUndef() ||
- V.getAs<loc::ConcreteInt>() || V.getAs<nonloc::ConcreteInt>()) {
- if (!IsParam)
- InitE = InitE->IgnoreParenCasts();
- bugreporter::trackExpressionValue(StoreSite, InitE, BR,
- EnableNullFPSuppression);
- }
- ReturnVisitor::addVisitorIfNecessary(StoreSite, InitE->IgnoreParenCasts(),
- BR, EnableNullFPSuppression);
+ if (!IsParam)
+ InitE = InitE->IgnoreParenCasts();
+
+ bugreporter::trackExpressionValue(
+ StoreSite, InitE, BR, TKind, EnableNullFPSuppression);
}
+ if (TKind == TrackingKind::Condition &&
+ !OriginSFC->isParentOf(StoreSite->getStackFrame()))
+ return nullptr;
+
// Okay, we've found the binding. Emit an appropriate message.
SmallString<256> sbuf;
llvm::raw_svector_ostream os(sbuf);
@@ -1411,8 +1484,8 @@ FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) {
if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
if (auto KV = State->getSVal(OriginalR).getAs<KnownSVal>())
- BR.addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
- *KV, OriginalR, EnableNullFPSuppression));
+ BR.addVisitor(std::make_unique<FindLastStoreBRVisitor>(
+ *KV, OriginalR, EnableNullFPSuppression, TKind, OriginSFC));
}
}
}
@@ -1428,6 +1501,9 @@ FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
if (os.str().empty())
showBRDefaultDiagnostics(os, R, V);
+ if (TKind == bugreporter::TrackingKind::Condition)
+ os << WillBeUsedForACondition;
+
// Construct a new PathDiagnosticPiece.
ProgramPoint P = StoreSite->getLocation();
PathDiagnosticLocation L;
@@ -1467,9 +1543,8 @@ bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const {
return (bool)N->getState()->assume(Constraint, !Assumption);
}
-std::shared_ptr<PathDiagnosticPiece>
-TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC, BugReport &) {
+PathDiagnosticPieceRef TrackConstraintBRVisitor::VisitNode(
+ const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &) {
const ExplodedNode *PrevN = N->getFirstPred();
if (IsSatisfied)
return nullptr;
@@ -1547,10 +1622,10 @@ const char *SuppressInlineDefensiveChecksVisitor::getTag() {
return "IDCVisitor";
}
-std::shared_ptr<PathDiagnosticPiece>
+PathDiagnosticPieceRef
SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ,
BugReporterContext &BRC,
- BugReport &BR) {
+ PathSensitiveBugReport &BR) {
const ExplodedNode *Pred = Succ->getFirstPred();
if (IsSatisfied)
return nullptr;
@@ -1649,24 +1724,12 @@ public:
ID.AddPointer(&x);
}
- std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- BugReport &BR) override;
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
};
} // end of anonymous namespace
-static CFGBlock *GetRelevantBlock(const ExplodedNode *Node) {
- if (auto SP = Node->getLocationAs<StmtPoint>()) {
- const Stmt *S = SP->getStmt();
- assert(S);
-
- return const_cast<CFGBlock *>(Node->getLocationContext()
- ->getAnalysisDeclContext()->getCFGStmtMap()->getBlock(S));
- }
-
- return nullptr;
-}
-
static std::shared_ptr<PathDiagnosticEventPiece>
constructDebugPieceForTrackedCondition(const Expr *Cond,
const ExplodedNode *N,
@@ -1687,34 +1750,75 @@ constructDebugPieceForTrackedCondition(const Expr *Cond,
(Twine() + "Tracking condition '" + ConditionText + "'").str());
}
-std::shared_ptr<PathDiagnosticPiece>
+static bool isAssertlikeBlock(const CFGBlock *B, ASTContext &Context) {
+ if (B->succ_size() != 2)
+ return false;
+
+ const CFGBlock *Then = B->succ_begin()->getReachableBlock();
+ const CFGBlock *Else = (B->succ_begin() + 1)->getReachableBlock();
+
+ if (!Then || !Else)
+ return false;
+
+ if (Then->isInevitablySinking() != Else->isInevitablySinking())
+ return true;
+
+ // For the following condition the following CFG would be built:
+ //
+ // ------------->
+ // / \
+ // [B1] -> [B2] -> [B3] -> [sink]
+ // assert(A && B || C); \ \
+ // -----------> [go on with the execution]
+ //
+ // It so happens that CFGBlock::getTerminatorCondition returns 'A' for block
+ // B1, 'A && B' for B2, and 'A && B || C' for B3. Let's check whether we
+ // reached the end of the condition!
+ if (const Stmt *ElseCond = Else->getTerminatorCondition())
+ if (const auto *BinOp = dyn_cast<BinaryOperator>(ElseCond))
+ if (BinOp->isLogicalOp())
+ return isAssertlikeBlock(Else, Context);
+
+ return false;
+}
+
+PathDiagnosticPieceRef
TrackControlDependencyCondBRVisitor::VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
- BugReport &BR) {
+ PathSensitiveBugReport &BR) {
// We can only reason about control dependencies within the same stack frame.
if (Origin->getStackFrame() != N->getStackFrame())
return nullptr;
- CFGBlock *NB = GetRelevantBlock(N);
+ CFGBlock *NB = const_cast<CFGBlock *>(N->getCFGBlock());
// Skip if we already inspected this block.
if (!VisitedBlocks.insert(NB).second)
return nullptr;
- CFGBlock *OriginB = GetRelevantBlock(Origin);
+ CFGBlock *OriginB = const_cast<CFGBlock *>(Origin->getCFGBlock());
// TODO: Cache CFGBlocks for each ExplodedNode.
if (!OriginB || !NB)
return nullptr;
+ if (isAssertlikeBlock(NB, BRC.getASTContext()))
+ return nullptr;
+
if (ControlDeps.isControlDependent(OriginB, NB)) {
+ // We don't really want to explain for range loops. Evidence suggests that
+ // the only thing that leads to is the addition of calls to operator!=.
+ if (llvm::isa_and_nonnull<CXXForRangeStmt>(NB->getTerminatorStmt()))
+ return nullptr;
+
if (const Expr *Condition = NB->getLastCondition()) {
// Keeping track of the already tracked conditions on a visitor level
// isn't sufficient, because a new visitor is created for each tracked
// expression, hence the BugReport level set.
if (BR.addTrackedCondition(N)) {
bugreporter::trackExpressionValue(
- N, Condition, BR, /*EnableNullFPSuppression=*/false);
+ N, Condition, BR, bugreporter::TrackingKind::Condition,
+ /*EnableNullFPSuppression=*/false);
return constructDebugPieceForTrackedCondition(Condition, N, BRC);
}
}
@@ -1819,7 +1923,7 @@ static const Expr *peelOffOuterExpr(const Expr *Ex,
static const ExplodedNode* findNodeForExpression(const ExplodedNode *N,
const Expr *Inner) {
while (N) {
- if (PathDiagnosticLocation::getStmt(N) == Inner)
+ if (N->getStmtForDiagnostics() == Inner)
return N;
N = N->getFirstPred();
}
@@ -1827,8 +1931,11 @@ static const ExplodedNode* findNodeForExpression(const ExplodedNode *N,
}
bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode,
- const Expr *E, BugReport &report,
+ const Expr *E,
+ PathSensitiveBugReport &report,
+ bugreporter::TrackingKind TKind,
bool EnableNullFPSuppression) {
+
if (!E || !InputNode)
return false;
@@ -1838,6 +1945,7 @@ bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode,
return false;
ProgramStateRef LVState = LVNode->getState();
+ const StackFrameContext *SFC = LVNode->getStackFrame();
// We only track expressions if we believe that they are important. Chances
// are good that control dependencies to the tracking point are also improtant
@@ -1845,19 +1953,20 @@ bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode,
// TODO: Shouldn't we track control dependencies of every bug location, rather
// than only tracked expressions?
if (LVState->getAnalysisManager().getAnalyzerOptions().ShouldTrackConditions)
- report.addVisitor(llvm::make_unique<TrackControlDependencyCondBRVisitor>(
+ report.addVisitor(std::make_unique<TrackControlDependencyCondBRVisitor>(
InputNode));
// The message send could be nil due to the receiver being nil.
// At this point in the path, the receiver should be live since we are at the
// message send expr. If it is nil, start tracking it.
if (const Expr *Receiver = NilReceiverBRVisitor::getNilReceiver(Inner, LVNode))
- trackExpressionValue(LVNode, Receiver, report, EnableNullFPSuppression);
+ trackExpressionValue(
+ LVNode, Receiver, report, TKind, EnableNullFPSuppression);
// Track the index if this is an array subscript.
if (const auto *Arr = dyn_cast<ArraySubscriptExpr>(Inner))
trackExpressionValue(
- LVNode, Arr->getIdx(), report, /*EnableNullFPSuppression*/ false);
+ LVNode, Arr->getIdx(), report, TKind, /*EnableNullFPSuppression*/false);
// See if the expression we're interested refers to a variable.
// If so, we can track both its contents and constraints on its value.
@@ -1872,8 +1981,8 @@ bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode,
// got initialized.
if (RR && !LVIsNull)
if (auto KV = LVal.getAs<KnownSVal>())
- report.addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
- *KV, RR, EnableNullFPSuppression));
+ report.addVisitor(std::make_unique<FindLastStoreBRVisitor>(
+ *KV, RR, EnableNullFPSuppression, TKind, SFC));
// In case of C++ references, we want to differentiate between a null
// reference and reference to null pointer.
@@ -1887,17 +1996,18 @@ bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode,
// Mark both the variable region and its contents as interesting.
SVal V = LVState->getRawSVal(loc::MemRegionVal(R));
report.addVisitor(
- llvm::make_unique<NoStoreFuncVisitor>(cast<SubRegion>(R)));
+ std::make_unique<NoStoreFuncVisitor>(cast<SubRegion>(R), TKind));
MacroNullReturnSuppressionVisitor::addMacroVisitorIfNecessary(
LVNode, R, EnableNullFPSuppression, report, V);
- report.markInteresting(V);
- report.addVisitor(llvm::make_unique<UndefOrNullArgVisitor>(R));
+ report.markInteresting(V, TKind);
+ report.addVisitor(std::make_unique<UndefOrNullArgVisitor>(R));
- // If the contents are symbolic, find out when they became null.
- if (V.getAsLocSymbol(/*IncludeBaseRegions*/ true))
- report.addVisitor(llvm::make_unique<TrackConstraintBRVisitor>(
+ // If the contents are symbolic and null, find out when they became null.
+ if (V.getAsLocSymbol(/*IncludeBaseRegions=*/true))
+ if (LVState->isNull(V).isConstrainedTrue())
+ report.addVisitor(std::make_unique<TrackConstraintBRVisitor>(
V.castAs<DefinedSVal>(), false));
// Add visitor, which will suppress inline defensive checks.
@@ -1905,12 +2015,12 @@ bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode,
if (!DV->isZeroConstant() && LVState->isNull(*DV).isConstrainedTrue() &&
EnableNullFPSuppression)
report.addVisitor(
- llvm::make_unique<SuppressInlineDefensiveChecksVisitor>(*DV,
+ std::make_unique<SuppressInlineDefensiveChecksVisitor>(*DV,
LVNode));
if (auto KV = V.getAs<KnownSVal>())
- report.addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
- *KV, R, EnableNullFPSuppression));
+ report.addVisitor(std::make_unique<FindLastStoreBRVisitor>(
+ *KV, R, EnableNullFPSuppression, TKind, SFC));
return true;
}
}
@@ -1920,40 +2030,43 @@ bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode,
SVal V = LVState->getSValAsScalarOrLoc(Inner, LVNode->getLocationContext());
ReturnVisitor::addVisitorIfNecessary(
- LVNode, Inner, report, EnableNullFPSuppression);
+ LVNode, Inner, report, EnableNullFPSuppression, TKind);
// Is it a symbolic value?
if (auto L = V.getAs<loc::MemRegionVal>()) {
- report.addVisitor(llvm::make_unique<UndefOrNullArgVisitor>(L->getRegion()));
-
// FIXME: this is a hack for fixing a later crash when attempting to
// dereference a void* pointer.
// We should not try to dereference pointers at all when we don't care
// what is written inside the pointer.
bool CanDereference = true;
- if (const auto *SR = dyn_cast<SymbolicRegion>(L->getRegion()))
+ if (const auto *SR = L->getRegionAs<SymbolicRegion>()) {
if (SR->getSymbol()->getType()->getPointeeType()->isVoidType())
CanDereference = false;
+ } else if (L->getRegionAs<AllocaRegion>())
+ CanDereference = false;
// At this point we are dealing with the region's LValue.
// However, if the rvalue is a symbolic region, we should track it as well.
// Try to use the correct type when looking up the value.
SVal RVal;
- if (ExplodedGraph::isInterestingLValueExpr(Inner)) {
+ if (ExplodedGraph::isInterestingLValueExpr(Inner))
RVal = LVState->getRawSVal(L.getValue(), Inner->getType());
- } else if (CanDereference) {
+ else if (CanDereference)
RVal = LVState->getSVal(L->getRegion());
- }
- if (CanDereference)
+ if (CanDereference) {
+ report.addVisitor(
+ std::make_unique<UndefOrNullArgVisitor>(L->getRegion()));
+
if (auto KV = RVal.getAs<KnownSVal>())
- report.addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
- *KV, L->getRegion(), EnableNullFPSuppression));
+ report.addVisitor(std::make_unique<FindLastStoreBRVisitor>(
+ *KV, L->getRegion(), EnableNullFPSuppression, TKind, SFC));
+ }
const MemRegion *RegionRVal = RVal.getAsRegion();
if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) {
- report.markInteresting(RegionRVal);
- report.addVisitor(llvm::make_unique<TrackConstraintBRVisitor>(
+ report.markInteresting(RegionRVal, TKind);
+ report.addVisitor(std::make_unique<TrackConstraintBRVisitor>(
loc::MemRegionVal(RegionRVal), /*assumption=*/false));
}
}
@@ -1978,9 +2091,9 @@ const Expr *NilReceiverBRVisitor::getNilReceiver(const Stmt *S,
return nullptr;
}
-std::shared_ptr<PathDiagnosticPiece>
-NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC, BugReport &BR) {
+PathDiagnosticPieceRef
+NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
Optional<PreStmt> P = N->getLocationAs<PreStmt>();
if (!P)
return nullptr;
@@ -2006,8 +2119,9 @@ 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.
- bugreporter::trackExpressionValue(N, Receiver, BR,
- /*EnableNullFPSuppression*/ false);
+ bugreporter::trackExpressionValue(
+ N, Receiver, BR, bugreporter::TrackingKind::Thorough,
+ /*EnableNullFPSuppression*/ false);
// Issue a message saying that the method was skipped.
PathDiagnosticLocation L(Receiver, BRC.getSourceManager(),
N->getLocationContext());
@@ -2015,57 +2129,16 @@ NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
}
//===----------------------------------------------------------------------===//
-// Implementation of FindLastStoreBRVisitor.
-//===----------------------------------------------------------------------===//
-
-// Registers every VarDecl inside a Stmt with a last store visitor.
-void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR,
- const Stmt *S,
- bool EnableNullFPSuppression) {
- const ExplodedNode *N = BR.getErrorNode();
- std::deque<const Stmt *> WorkList;
- WorkList.push_back(S);
-
- while (!WorkList.empty()) {
- const Stmt *Head = WorkList.front();
- WorkList.pop_front();
-
- ProgramStateManager &StateMgr = N->getState()->getStateManager();
-
- if (const auto *DR = dyn_cast<DeclRefExpr>(Head)) {
- if (const auto *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- const VarRegion *R =
- StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext());
-
- // What did we load?
- SVal V = N->getSVal(S);
-
- if (V.getAs<loc::ConcreteInt>() || V.getAs<nonloc::ConcreteInt>()) {
- // Register a new visitor with the BugReport.
- BR.addVisitor(llvm::make_unique<FindLastStoreBRVisitor>(
- V.castAs<KnownSVal>(), R, EnableNullFPSuppression));
- }
- }
- }
-
- for (const Stmt *SubStmt : Head->children())
- WorkList.push_back(SubStmt);
- }
-}
-
-//===----------------------------------------------------------------------===//
// Visitor that tries to report interesting diagnostics from conditions.
//===----------------------------------------------------------------------===//
/// Return the tag associated with this visitor. This tag will be used
/// to make all PathDiagnosticPieces created by this visitor.
-const char *ConditionBRVisitor::getTag() {
- return "ConditionBRVisitor";
-}
+const char *ConditionBRVisitor::getTag() { return "ConditionBRVisitor"; }
-std::shared_ptr<PathDiagnosticPiece>
-ConditionBRVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC, BugReport &BR) {
+PathDiagnosticPieceRef
+ConditionBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
auto piece = VisitNodeImpl(N, BRC, BR);
if (piece) {
piece->setTag(getTag());
@@ -2075,9 +2148,10 @@ ConditionBRVisitor::VisitNode(const ExplodedNode *N,
return piece;
}
-std::shared_ptr<PathDiagnosticPiece>
+PathDiagnosticPieceRef
ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
- BugReporterContext &BRC, BugReport &BR) {
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
ProgramPoint ProgPoint = N->getLocation();
const std::pair<const ProgramPointTag *, const ProgramPointTag *> &Tags =
ExprEngine::geteagerlyAssumeBinOpBifurcationTags();
@@ -2113,9 +2187,10 @@ ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
return nullptr;
}
-std::shared_ptr<PathDiagnosticPiece> ConditionBRVisitor::VisitTerminator(
+PathDiagnosticPieceRef ConditionBRVisitor::VisitTerminator(
const Stmt *Term, const ExplodedNode *N, const CFGBlock *srcBlk,
- const CFGBlock *dstBlk, BugReport &R, BugReporterContext &BRC) {
+ const CFGBlock *dstBlk, PathSensitiveBugReport &R,
+ BugReporterContext &BRC) {
const Expr *Cond = nullptr;
// In the code below, Term is a CFG terminator and Cond is a branch condition
@@ -2170,10 +2245,10 @@ std::shared_ptr<PathDiagnosticPiece> ConditionBRVisitor::VisitTerminator(
return VisitTrueTest(Cond, BRC, R, N, TookTrue);
}
-std::shared_ptr<PathDiagnosticPiece>
+PathDiagnosticPieceRef
ConditionBRVisitor::VisitTrueTest(const Expr *Cond, BugReporterContext &BRC,
- BugReport &R, const ExplodedNode *N,
- bool TookTrue) {
+ PathSensitiveBugReport &R,
+ const ExplodedNode *N, bool TookTrue) {
ProgramStateRef CurrentState = N->getState();
ProgramStateRef PrevState = N->getFirstPred()->getState();
const LocationContext *LCtx = N->getLocationContext();
@@ -2243,7 +2318,7 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex,
const Expr *ParentEx,
raw_ostream &Out,
BugReporterContext &BRC,
- BugReport &report,
+ PathSensitiveBugReport &report,
const ExplodedNode *N,
Optional<bool> &prunable,
bool IsSameFieldName) {
@@ -2258,7 +2333,7 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex,
SourceLocation BeginLoc = OriginalExpr->getBeginLoc();
SourceLocation EndLoc = OriginalExpr->getEndLoc();
if (BeginLoc.isMacroID() && EndLoc.isMacroID()) {
- SourceManager &SM = BRC.getSourceManager();
+ const SourceManager &SM = BRC.getSourceManager();
const LangOptions &LO = BRC.getASTContext().getLangOpts();
if (Lexer::isAtStartOfMacroExpansion(BeginLoc, SM, LO) &&
Lexer::isAtEndOfMacroExpansion(EndLoc, SM, LO)) {
@@ -2326,21 +2401,22 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex,
return false;
}
-std::shared_ptr<PathDiagnosticPiece> ConditionBRVisitor::VisitTrueTest(
+PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
const Expr *Cond, const BinaryOperator *BExpr, BugReporterContext &BRC,
- BugReport &R, const ExplodedNode *N, bool TookTrue, bool IsAssuming) {
+ PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue,
+ bool IsAssuming) {
bool shouldInvert = false;
Optional<bool> shouldPrune;
// Check if the field name of the MemberExprs is ambiguous. Example:
// " 'a.d' is equal to 'h.d' " in 'test/Analysis/null-deref-path-notes.cpp'.
bool IsSameFieldName = false;
- if (const auto *LhsME =
- dyn_cast<MemberExpr>(BExpr->getLHS()->IgnoreParenCasts()))
- if (const auto *RhsME =
- dyn_cast<MemberExpr>(BExpr->getRHS()->IgnoreParenCasts()))
- IsSameFieldName = LhsME->getMemberDecl()->getName() ==
- RhsME->getMemberDecl()->getName();
+ const auto *LhsME = dyn_cast<MemberExpr>(BExpr->getLHS()->IgnoreParenCasts());
+ const auto *RhsME = dyn_cast<MemberExpr>(BExpr->getRHS()->IgnoreParenCasts());
+
+ if (LhsME && RhsME)
+ IsSameFieldName =
+ LhsME->getMemberDecl()->getName() == RhsME->getMemberDecl()->getName();
SmallString<128> LhsString, RhsString;
{
@@ -2410,25 +2486,44 @@ std::shared_ptr<PathDiagnosticPiece> ConditionBRVisitor::VisitTrueTest(
Out << (shouldInvert ? LhsString : RhsString);
const LocationContext *LCtx = N->getLocationContext();
- PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
+ const SourceManager &SM = BRC.getSourceManager();
+
+ if (isVarAnInterestingCondition(BExpr->getLHS(), N, &R) ||
+ isVarAnInterestingCondition(BExpr->getRHS(), N, &R))
+ Out << WillBeUsedForACondition;
// Convert 'field ...' to 'Field ...' if it is a MemberExpr.
std::string Message = Out.str();
Message[0] = toupper(Message[0]);
- // If we know the value create a pop-up note.
- if (!IsAssuming)
+ // If we know the value create a pop-up note to the value part of 'BExpr'.
+ if (!IsAssuming) {
+ PathDiagnosticLocation Loc;
+ if (!shouldInvert) {
+ if (LhsME && LhsME->getMemberLoc().isValid())
+ Loc = PathDiagnosticLocation(LhsME->getMemberLoc(), SM);
+ else
+ Loc = PathDiagnosticLocation(BExpr->getLHS(), SM, LCtx);
+ } else {
+ if (RhsME && RhsME->getMemberLoc().isValid())
+ Loc = PathDiagnosticLocation(RhsME->getMemberLoc(), SM);
+ else
+ Loc = PathDiagnosticLocation(BExpr->getRHS(), SM, LCtx);
+ }
+
return std::make_shared<PathDiagnosticPopUpPiece>(Loc, Message);
+ }
+ PathDiagnosticLocation Loc(Cond, SM, LCtx);
auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Message);
if (shouldPrune.hasValue())
event->setPrunable(shouldPrune.getValue());
return event;
}
-std::shared_ptr<PathDiagnosticPiece> ConditionBRVisitor::VisitConditionVariable(
+PathDiagnosticPieceRef ConditionBRVisitor::VisitConditionVariable(
StringRef LhsString, const Expr *CondVarExpr, BugReporterContext &BRC,
- BugReport &report, const ExplodedNode *N, bool TookTrue) {
+ PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue) {
// FIXME: If there's already a constraint tracker for this variable,
// we shouldn't emit anything here (c.f. the double note in
// test/Analysis/inlining/path-notes.c)
@@ -2441,24 +2536,22 @@ std::shared_ptr<PathDiagnosticPiece> ConditionBRVisitor::VisitConditionVariable(
const LocationContext *LCtx = N->getLocationContext();
PathDiagnosticLocation Loc(CondVarExpr, BRC.getSourceManager(), LCtx);
+
+ if (isVarAnInterestingCondition(CondVarExpr, N, &report))
+ Out << WillBeUsedForACondition;
+
auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Out.str());
- if (const auto *DR = dyn_cast<DeclRefExpr>(CondVarExpr)) {
- if (const auto *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- const ProgramState *state = N->getState().get();
- if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) {
- if (report.isInteresting(R))
- event->setPrunable(false);
- }
- }
- }
+ if (isInterestingExpr(CondVarExpr, N, &report))
+ event->setPrunable(false);
return event;
}
-std::shared_ptr<PathDiagnosticPiece> ConditionBRVisitor::VisitTrueTest(
+PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
const Expr *Cond, const DeclRefExpr *DRE, BugReporterContext &BRC,
- BugReport &report, const ExplodedNode *N, bool TookTrue, bool IsAssuming) {
+ PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue,
+ bool IsAssuming) {
const auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
if (!VD)
return nullptr;
@@ -2472,29 +2565,29 @@ std::shared_ptr<PathDiagnosticPiece> ConditionBRVisitor::VisitTrueTest(
return nullptr;
const LocationContext *LCtx = N->getLocationContext();
- PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
- // If we know the value create a pop-up note.
- if (!IsAssuming)
+ if (isVarAnInterestingCondition(DRE, N, &report))
+ Out << WillBeUsedForACondition;
+
+ // If we know the value create a pop-up note to the 'DRE'.
+ if (!IsAssuming) {
+ PathDiagnosticLocation Loc(DRE, BRC.getSourceManager(), LCtx);
return std::make_shared<PathDiagnosticPopUpPiece>(Loc, Out.str());
+ }
+ PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Out.str());
- const ProgramState *state = N->getState().get();
- 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);
- }
- }
+
+ if (isInterestingExpr(DRE, N, &report))
+ event->setPrunable(false);
+
return std::move(event);
}
-std::shared_ptr<PathDiagnosticPiece> ConditionBRVisitor::VisitTrueTest(
+PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
const Expr *Cond, const MemberExpr *ME, BugReporterContext &BRC,
- BugReport &report, const ExplodedNode *N, bool TookTrue, bool IsAssuming) {
+ PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue,
+ bool IsAssuming) {
SmallString<256> Buf;
llvm::raw_svector_ostream Out(Buf);
@@ -2505,15 +2598,28 @@ std::shared_ptr<PathDiagnosticPiece> ConditionBRVisitor::VisitTrueTest(
return nullptr;
const LocationContext *LCtx = N->getLocationContext();
- PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
+ PathDiagnosticLocation Loc;
+
+ // If we know the value create a pop-up note to the member of the MemberExpr.
+ if (!IsAssuming && ME->getMemberLoc().isValid())
+ Loc = PathDiagnosticLocation(ME->getMemberLoc(), BRC.getSourceManager());
+ else
+ Loc = PathDiagnosticLocation(Cond, BRC.getSourceManager(), LCtx);
+
if (!Loc.isValid() || !Loc.asLocation().isValid())
return nullptr;
+ if (isVarAnInterestingCondition(ME, N, &report))
+ Out << WillBeUsedForACondition;
+
// If we know the value create a pop-up note.
if (!IsAssuming)
return std::make_shared<PathDiagnosticPopUpPiece>(Loc, Out.str());
- return std::make_shared<PathDiagnosticEventPiece>(Loc, Out.str());
+ auto event = std::make_shared<PathDiagnosticEventPiece>(Loc, Out.str());
+ if (isInterestingExpr(ME, N, &report))
+ event->setPrunable(false);
+ return event;
}
bool ConditionBRVisitor::printValue(const Expr *CondVarExpr, raw_ostream &Out,
@@ -2553,10 +2659,8 @@ bool ConditionBRVisitor::printValue(const Expr *CondVarExpr, raw_ostream &Out,
return true;
}
-const char *const ConditionBRVisitor::GenericTrueMessage =
- "Assuming the condition is true";
-const char *const ConditionBRVisitor::GenericFalseMessage =
- "Assuming the condition is false";
+constexpr llvm::StringLiteral ConditionBRVisitor::GenericTrueMessage;
+constexpr llvm::StringLiteral ConditionBRVisitor::GenericFalseMessage;
bool ConditionBRVisitor::isPieceMessageGeneric(
const PathDiagnosticPiece *Piece) {
@@ -2569,10 +2673,11 @@ bool ConditionBRVisitor::isPieceMessageGeneric(
//===----------------------------------------------------------------------===//
void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
- BugReporterContext &BRC, const ExplodedNode *N, BugReport &BR) {
+ BugReporterContext &BRC, const ExplodedNode *N,
+ PathSensitiveBugReport &BR) {
// Here we suppress false positives coming from system headers. This list is
// based on known issues.
- AnalyzerOptions &Options = BRC.getAnalyzerOptions();
+ const AnalyzerOptions &Options = BRC.getAnalyzerOptions();
const Decl *D = N->getLocationContext()->getDecl();
if (AnalysisDeclContext::isInStdNamespace(D)) {
@@ -2639,8 +2744,8 @@ void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
// Skip reports within the sys/queue.h macros as we do not have the ability to
// reason about data structure shapes.
- SourceManager &SM = BRC.getSourceManager();
- FullSourceLoc Loc = BR.getLocation(SM).asLocation();
+ const SourceManager &SM = BRC.getSourceManager();
+ FullSourceLoc Loc = BR.getLocation().asLocation();
while (Loc.isMacroID()) {
Loc = Loc.getSpellingLoc();
if (SM.getFilename(Loc).endswith("sys/queue.h")) {
@@ -2654,9 +2759,9 @@ void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
// Implementation of UndefOrNullArgVisitor.
//===----------------------------------------------------------------------===//
-std::shared_ptr<PathDiagnosticPiece>
-UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC, BugReport &BR) {
+PathDiagnosticPieceRef
+UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
ProgramStateRef State = N->getState();
ProgramPoint ProgLoc = N->getLocation();
@@ -2712,7 +2817,8 @@ FalsePositiveRefutationBRVisitor::FalsePositiveRefutationBRVisitor()
: Constraints(ConstraintRangeTy::Factory().getEmptyMap()) {}
void FalsePositiveRefutationBRVisitor::finalizeVisitor(
- BugReporterContext &BRC, const ExplodedNode *EndPathNode, BugReport &BR) {
+ BugReporterContext &BRC, const ExplodedNode *EndPathNode,
+ PathSensitiveBugReport &BR) {
// Collect new constraints
VisitNode(EndPathNode, BRC, BR);
@@ -2747,10 +2853,8 @@ void FalsePositiveRefutationBRVisitor::finalizeVisitor(
BR.markInvalid("Infeasible constraints", EndPathNode->getLocationContext());
}
-std::shared_ptr<PathDiagnosticPiece>
-FalsePositiveRefutationBRVisitor::VisitNode(const ExplodedNode *N,
- BugReporterContext &,
- BugReport &) {
+PathDiagnosticPieceRef FalsePositiveRefutationBRVisitor::VisitNode(
+ const ExplodedNode *N, BugReporterContext &, PathSensitiveBugReport &) {
// Collect new constraints
const ConstraintRangeTy &NewCs = N->getState()->get<ConstraintRange>();
ConstraintRangeTy::Factory &CF =
@@ -2784,9 +2888,9 @@ void TagVisitor::Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(&Tag);
}
-std::shared_ptr<PathDiagnosticPiece>
-TagVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
- BugReport &R) {
+PathDiagnosticPieceRef TagVisitor::VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &R) {
ProgramPoint PP = N->getLocation();
const NoteTag *T = dyn_cast_or_null<NoteTag>(PP.getTag());
if (!T)
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index a5f7500e6307..5f04a59ba055 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -27,6 +27,7 @@
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/CrossTU/CrossTranslationUnit.h"
#include "clang/Basic/IdentifierTable.h"
@@ -34,10 +35,9 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Specifiers.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
@@ -191,7 +191,8 @@ AnalysisDeclContext *CallEvent::getCalleeAnalysisDeclContext() const {
return ADC;
}
-const StackFrameContext *CallEvent::getCalleeStackFrame() const {
+const StackFrameContext *
+CallEvent::getCalleeStackFrame(unsigned BlockCount) const {
AnalysisDeclContext *ADC = getCalleeAnalysisDeclContext();
if (!ADC)
return nullptr;
@@ -217,11 +218,12 @@ const StackFrameContext *CallEvent::getCalleeStackFrame() const {
break;
assert(Idx < Sz);
- return ADC->getManager()->getStackFrame(ADC, LCtx, E, B, Idx);
+ return ADC->getManager()->getStackFrame(ADC, LCtx, E, B, BlockCount, Idx);
}
-const VarRegion *CallEvent::getParameterLocation(unsigned Index) const {
- const StackFrameContext *SFC = getCalleeStackFrame();
+const VarRegion *CallEvent::getParameterLocation(unsigned Index,
+ unsigned BlockCount) const {
+ const StackFrameContext *SFC = getCalleeStackFrame(BlockCount);
// We cannot construct a VarRegion without a stack frame.
if (!SFC)
return nullptr;
@@ -322,7 +324,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
if (getKind() != CE_CXXAllocator)
if (isArgumentConstructedDirectly(Idx))
if (auto AdjIdx = getAdjustedParameterIndex(Idx))
- if (const VarRegion *VR = getParameterLocation(*AdjIdx))
+ if (const VarRegion *VR = getParameterLocation(*AdjIdx, BlockCount))
ValuesToInvalidate.push_back(loc::MemRegionVal(VR));
}
@@ -366,7 +368,8 @@ bool CallEvent::isCalled(const CallDescription &CD) const {
if (CD.Flags & CDF_MaybeBuiltin) {
return CheckerContext::isCLibraryFunction(FD, CD.getFunctionName()) &&
- (!CD.RequiredArgs || CD.RequiredArgs <= getNumArgs());
+ (!CD.RequiredArgs || CD.RequiredArgs <= getNumArgs()) &&
+ (!CD.RequiredParams || CD.RequiredParams <= parameters().size());
}
if (!CD.IsLookupDone) {
@@ -405,7 +408,8 @@ bool CallEvent::isCalled(const CallDescription &CD) const {
return false;
}
- return (!CD.RequiredArgs || CD.RequiredArgs == getNumArgs());
+ return (!CD.RequiredArgs || CD.RequiredArgs == getNumArgs()) &&
+ (!CD.RequiredParams || CD.RequiredParams == parameters().size());
}
SVal CallEvent::getArgSVal(unsigned Index) const {
@@ -1033,7 +1037,7 @@ getSyntacticFromForPseudoObjectExpr(const PseudoObjectExpr *POE) {
ObjCMessageKind ObjCMethodCall::getMessageKind() const {
if (!Data) {
// Find the parent, ignoring implicit casts.
- ParentMap &PM = getLocationContext()->getParentMap();
+ const ParentMap &PM = getLocationContext()->getParentMap();
const Stmt *S = PM.getParentIgnoreParenCasts(getOriginExpr());
// Check if parent is a PseudoObjectExpr.
diff --git a/lib/StaticAnalyzer/Core/Checker.cpp b/lib/StaticAnalyzer/Core/Checker.cpp
index f4e6f909d764..bc1c8964b3ee 100644
--- a/lib/StaticAnalyzer/Core/Checker.cpp
+++ b/lib/StaticAnalyzer/Core/Checker.cpp
@@ -19,10 +19,10 @@ using namespace ento;
int ImplicitNullDerefEvent::Tag;
StringRef CheckerBase::getTagDescription() const {
- return getCheckName().getName();
+ return getCheckerName().getName();
}
-CheckName CheckerBase::getCheckName() const { return Name; }
+CheckerNameRef CheckerBase::getCheckerName() const { return Name; }
CheckerProgramPointTag::CheckerProgramPointTag(StringRef CheckerName,
StringRef Msg)
@@ -30,10 +30,10 @@ CheckerProgramPointTag::CheckerProgramPointTag(StringRef CheckerName,
CheckerProgramPointTag::CheckerProgramPointTag(const CheckerBase *Checker,
StringRef Msg)
- : SimpleProgramPointTag(Checker->getCheckName().getName(), Msg) {}
+ : SimpleProgramPointTag(Checker->getCheckerName().getName(), Msg) {}
raw_ostream& clang::ento::operator<<(raw_ostream &Out,
const CheckerBase &Checker) {
- Out << Checker.getCheckName().getName();
+ Out << Checker.getCheckerName().getName();
return Out;
}
diff --git a/lib/StaticAnalyzer/Core/CheckerHelpers.cpp b/lib/StaticAnalyzer/Core/CheckerHelpers.cpp
index 34cdc9db699d..11693132de68 100644
--- a/lib/StaticAnalyzer/Core/CheckerHelpers.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerHelpers.cpp
@@ -91,7 +91,7 @@ parseAssignment(const Stmt *S) {
} else if (auto PD = dyn_cast_or_null<DeclStmt>(S)) {
// Initialization
assert(PD->isSingleDecl() && "We process decls one by one");
- VD = dyn_cast_or_null<VarDecl>(PD->getSingleDecl());
+ VD = cast<VarDecl>(PD->getSingleDecl());
RHS = VD->getAnyInitializer();
}
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 27d5797b4cbc..f676bd895283 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -748,7 +748,7 @@ void CheckerManager::runCheckersForPrintStateJson(raw_ostream &Out,
continue;
Indent(Out, Space, IsDot)
- << "{ \"checker\": \"" << CT.second->getCheckName().getName()
+ << "{ \"checker\": \"" << CT.second->getCheckerName().getName()
<< "\", \"messages\": [" << NL;
Indent(Out, InnerSpace, IsDot)
<< '\"' << TempBuf.str().trim() << '\"' << NL;
diff --git a/lib/StaticAnalyzer/Core/CommonBugCategories.cpp b/lib/StaticAnalyzer/Core/CommonBugCategories.cpp
index 54501314386a..bdae3e605eff 100644
--- a/lib/StaticAnalyzer/Core/CommonBugCategories.cpp
+++ b/lib/StaticAnalyzer/Core/CommonBugCategories.cpp
@@ -17,4 +17,5 @@ const char * const MemoryRefCount =
"Memory (Core Foundation/Objective-C/OSObject)";
const char * const MemoryError = "Memory error";
const char * const UnixAPI = "Unix API";
+const char * const CXXObjectLifecycle = "C++ object lifecycle";
}}}
diff --git a/lib/StaticAnalyzer/Core/DynamicType.cpp b/lib/StaticAnalyzer/Core/DynamicType.cpp
new file mode 100644
index 000000000000..a78e0e05e903
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/DynamicType.cpp
@@ -0,0 +1,229 @@
+//===- DynamicType.cpp - Dynamic type related APIs --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines APIs that track and query dynamic type information. This
+// information can be used to devirtualize calls during the symbolic execution
+// or do type checking.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
+#include "clang/Basic/JsonSupport.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+
+/// The GDM component containing the dynamic type info. This is a map from a
+/// symbol to its most likely type.
+REGISTER_MAP_WITH_PROGRAMSTATE(DynamicTypeMap, const clang::ento::MemRegion *,
+ clang::ento::DynamicTypeInfo)
+
+/// A set factory of dynamic cast informations.
+REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(CastSet, clang::ento::DynamicCastInfo)
+
+/// A map from symbols to cast informations.
+REGISTER_MAP_WITH_PROGRAMSTATE(DynamicCastMap, const clang::ento::MemRegion *,
+ CastSet)
+
+namespace clang {
+namespace ento {
+
+DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR) {
+ MR = MR->StripCasts();
+
+ // Look up the dynamic type in the GDM.
+ if (const DynamicTypeInfo *DTI = State->get<DynamicTypeMap>(MR))
+ return *DTI;
+
+ // Otherwise, fall back to what we know about the region.
+ if (const auto *TR = dyn_cast<TypedRegion>(MR))
+ return DynamicTypeInfo(TR->getLocationType(), /*CanBeSub=*/false);
+
+ if (const auto *SR = dyn_cast<SymbolicRegion>(MR)) {
+ SymbolRef Sym = SR->getSymbol();
+ return DynamicTypeInfo(Sym->getType());
+ }
+
+ return {};
+}
+
+const DynamicTypeInfo *getRawDynamicTypeInfo(ProgramStateRef State,
+ const MemRegion *MR) {
+ return State->get<DynamicTypeMap>(MR);
+}
+
+const DynamicCastInfo *getDynamicCastInfo(ProgramStateRef State,
+ const MemRegion *MR,
+ QualType CastFromTy,
+ QualType CastToTy) {
+ const auto *Lookup = State->get<DynamicCastMap>().lookup(MR);
+ if (!Lookup)
+ return nullptr;
+
+ for (const DynamicCastInfo &Cast : *Lookup)
+ if (Cast.equals(CastFromTy, CastToTy))
+ return &Cast;
+
+ return nullptr;
+}
+
+ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR,
+ DynamicTypeInfo NewTy) {
+ State = State->set<DynamicTypeMap>(MR->StripCasts(), NewTy);
+ assert(State);
+ return State;
+}
+
+ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR,
+ QualType NewTy, bool CanBeSubClassed) {
+ return setDynamicTypeInfo(State, MR, DynamicTypeInfo(NewTy, CanBeSubClassed));
+}
+
+ProgramStateRef setDynamicTypeAndCastInfo(ProgramStateRef State,
+ const MemRegion *MR,
+ QualType CastFromTy,
+ QualType CastToTy,
+ bool CastSucceeds) {
+ if (!MR)
+ return State;
+
+ if (CastSucceeds) {
+ assert((CastToTy->isAnyPointerType() || CastToTy->isReferenceType()) &&
+ "DynamicTypeInfo should always be a pointer.");
+ State = State->set<DynamicTypeMap>(MR, CastToTy);
+ }
+
+ DynamicCastInfo::CastResult ResultKind =
+ CastSucceeds ? DynamicCastInfo::CastResult::Success
+ : DynamicCastInfo::CastResult::Failure;
+
+ CastSet::Factory &F = State->get_context<CastSet>();
+
+ const CastSet *TempSet = State->get<DynamicCastMap>(MR);
+ CastSet Set = TempSet ? *TempSet : F.getEmptySet();
+
+ Set = F.add(Set, {CastFromTy, CastToTy, ResultKind});
+ State = State->set<DynamicCastMap>(MR, Set);
+
+ assert(State);
+ return State;
+}
+
+template <typename MapTy>
+ProgramStateRef removeDead(ProgramStateRef State, const MapTy &Map,
+ SymbolReaper &SR) {
+ for (const auto &Elem : Map)
+ if (!SR.isLiveRegion(Elem.first))
+ State = State->remove<DynamicCastMap>(Elem.first);
+
+ return State;
+}
+
+ProgramStateRef removeDeadTypes(ProgramStateRef State, SymbolReaper &SR) {
+ return removeDead(State, State->get<DynamicTypeMap>(), SR);
+}
+
+ProgramStateRef removeDeadCasts(ProgramStateRef State, SymbolReaper &SR) {
+ return removeDead(State, State->get<DynamicCastMap>(), SR);
+}
+
+static void printDynamicTypesJson(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, unsigned int Space,
+ bool IsDot) {
+ Indent(Out, Space, IsDot) << "\"dynamic_types\": ";
+
+ const DynamicTypeMapTy &Map = State->get<DynamicTypeMap>();
+ if (Map.isEmpty()) {
+ Out << "null," << NL;
+ return;
+ }
+
+ ++Space;
+ Out << '[' << NL;
+ for (DynamicTypeMapTy::iterator I = Map.begin(); I != Map.end(); ++I) {
+ const MemRegion *MR = I->first;
+ const DynamicTypeInfo &DTI = I->second;
+ Indent(Out, Space, IsDot)
+ << "{ \"region\": \"" << MR << "\", \"dyn_type\": ";
+ if (!DTI.isValid()) {
+ Out << "null";
+ } else {
+ Out << '\"' << DTI.getType()->getPointeeType().getAsString()
+ << "\", \"sub_classable\": "
+ << (DTI.canBeASubClass() ? "true" : "false");
+ }
+ Out << " }";
+
+ if (std::next(I) != Map.end())
+ Out << ',';
+ Out << NL;
+ }
+
+ --Space;
+ Indent(Out, Space, IsDot) << "]," << NL;
+}
+
+static void printDynamicCastsJson(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, unsigned int Space,
+ bool IsDot) {
+ Indent(Out, Space, IsDot) << "\"dynamic_casts\": ";
+
+ const DynamicCastMapTy &Map = State->get<DynamicCastMap>();
+ if (Map.isEmpty()) {
+ Out << "null," << NL;
+ return;
+ }
+
+ ++Space;
+ Out << '[' << NL;
+ for (DynamicCastMapTy::iterator I = Map.begin(); I != Map.end(); ++I) {
+ const MemRegion *MR = I->first;
+ const CastSet &Set = I->second;
+
+ Indent(Out, Space, IsDot) << "{ \"region\": \"" << MR << "\", \"casts\": ";
+ if (Set.isEmpty()) {
+ Out << "null ";
+ } else {
+ ++Space;
+ Out << '[' << NL;
+ for (CastSet::iterator SI = Set.begin(); SI != Set.end(); ++SI) {
+ Indent(Out, Space, IsDot)
+ << "{ \"from\": \"" << SI->from().getAsString() << "\", \"to\": \""
+ << SI->to().getAsString() << "\", \"kind\": \""
+ << (SI->succeeds() ? "success" : "fail") << "\" }";
+
+ if (std::next(SI) != Set.end())
+ Out << ',';
+ Out << NL;
+ }
+ --Space;
+ Indent(Out, Space, IsDot) << ']';
+ }
+ Out << '}';
+
+ if (std::next(I) != Map.end())
+ Out << ',';
+ Out << NL;
+ }
+
+ --Space;
+ Indent(Out, Space, IsDot) << "]," << NL;
+}
+
+void printDynamicTypeInfoJson(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, unsigned int Space, bool IsDot) {
+ printDynamicTypesJson(Out, State, NL, Space, IsDot);
+ printDynamicCastsJson(Out, State, NL, Space, IsDot);
+}
+
+} // namespace ento
+} // namespace clang
diff --git a/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp b/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp
deleted file mode 100644
index 79424452240d..000000000000
--- a/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-//===- DynamicTypeMap.cpp - Dynamic Type Info related APIs ----------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines APIs that track and query dynamic type information. This
-// information can be used to devirtualize calls during the symbolic execution
-// or do type checking.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
-#include "clang/Basic/JsonSupport.h"
-#include "clang/Basic/LLVM.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cassert>
-
-namespace clang {
-namespace ento {
-
-DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State,
- const MemRegion *Reg) {
- Reg = Reg->StripCasts();
-
- // Look up the dynamic type in the GDM.
- const DynamicTypeInfo *GDMType = State->get<DynamicTypeMap>(Reg);
- if (GDMType)
- return *GDMType;
-
- // Otherwise, fall back to what we know about the region.
- if (const auto *TR = dyn_cast<TypedRegion>(Reg))
- return DynamicTypeInfo(TR->getLocationType(), /*CanBeSub=*/false);
-
- if (const auto *SR = dyn_cast<SymbolicRegion>(Reg)) {
- SymbolRef Sym = SR->getSymbol();
- return DynamicTypeInfo(Sym->getType());
- }
-
- return {};
-}
-
-ProgramStateRef setDynamicTypeInfo(ProgramStateRef State, const MemRegion *Reg,
- DynamicTypeInfo NewTy) {
- Reg = Reg->StripCasts();
- ProgramStateRef NewState = State->set<DynamicTypeMap>(Reg, NewTy);
- assert(NewState);
- return NewState;
-}
-
-void printDynamicTypeInfoJson(raw_ostream &Out, ProgramStateRef State,
- const char *NL, unsigned int Space, bool IsDot) {
- Indent(Out, Space, IsDot) << "\"dynamic_types\": ";
-
- const DynamicTypeMapTy &DTM = State->get<DynamicTypeMap>();
- if (DTM.isEmpty()) {
- Out << "null," << NL;
- return;
- }
-
- ++Space;
- Out << '[' << NL;
- for (DynamicTypeMapTy::iterator I = DTM.begin(); I != DTM.end(); ++I) {
- const MemRegion *MR = I->first;
- const DynamicTypeInfo &DTI = I->second;
- Out << "{ \"region\": \"" << MR << "\", \"dyn_type\": ";
- if (DTI.isValid()) {
- Out << '\"' << DTI.getType()->getPointeeType().getAsString()
- << "\", \"sub_classable\": "
- << (DTI.canBeASubClass() ? "true" : "false");
- } else {
- Out << "null"; // Invalid type info
- }
- Out << "}";
-
- if (std::next(I) != DTM.end())
- Out << ',';
- Out << NL;
- }
-
- --Space;
- Indent(Out, Space, IsDot) << "]," << NL;
-}
-
-void *ProgramStateTrait<DynamicTypeMap>::GDMIndex() {
- static int index = 0;
- return &index;
-}
-
-} // namespace ento
-} // namespace clang
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index 551c89b04db4..1ccf4c6104a6 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -108,6 +108,7 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry,
case Stmt::ObjCStringLiteralClass:
case Stmt::StringLiteralClass:
case Stmt::TypeTraitExprClass:
+ case Stmt::SizeOfPackExprClass:
// Known constants; defer to SValBuilder.
return svalBuilder.getConstantVal(cast<Expr>(S)).getValue();
diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index c86b1436baab..c4838492271c 100644
--- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/Stmt.h"
+#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Analysis/Support/BumpVector.h"
#include "clang/Basic/LLVM.h"
@@ -134,7 +135,7 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
// Do not collect nodes for non-consumed Stmt or Expr to ensure precise
// diagnostic generation; specifically, so that we could anchor arrows
// pointing to the beginning of statements (as written in code).
- ParentMap &PM = progPoint.getLocationContext()->getParentMap();
+ const ParentMap &PM = progPoint.getLocationContext()->getParentMap();
if (!PM.isConsumedExpr(Ex))
return false;
@@ -282,16 +283,115 @@ ExplodedNode * const *ExplodedNode::NodeGroup::end() const {
return Storage.getAddrOfPtr1() + 1;
}
-int64_t ExplodedNode::getID(ExplodedGraph *G) const {
- return G->getAllocator().identifyKnownAlignedObject<ExplodedNode>(this);
-}
-
bool ExplodedNode::isTrivial() const {
return pred_size() == 1 && succ_size() == 1 &&
getFirstPred()->getState()->getID() == getState()->getID() &&
getFirstPred()->succ_size() == 1;
}
+const CFGBlock *ExplodedNode::getCFGBlock() const {
+ ProgramPoint P = getLocation();
+ if (auto BEP = P.getAs<BlockEntrance>())
+ return BEP->getBlock();
+
+ // Find the node's current statement in the CFG.
+ // FIXME: getStmtForDiagnostics() does nasty things in order to provide
+ // a valid statement for body farms, do we need this behavior here?
+ if (const Stmt *S = getStmtForDiagnostics())
+ return getLocationContext()
+ ->getAnalysisDeclContext()
+ ->getCFGStmtMap()
+ ->getBlock(S);
+
+ return nullptr;
+}
+
+static const LocationContext *
+findTopAutosynthesizedParentContext(const LocationContext *LC) {
+ assert(LC->getAnalysisDeclContext()->isBodyAutosynthesized());
+ const LocationContext *ParentLC = LC->getParent();
+ assert(ParentLC && "We don't start analysis from autosynthesized code");
+ while (ParentLC->getAnalysisDeclContext()->isBodyAutosynthesized()) {
+ LC = ParentLC;
+ ParentLC = LC->getParent();
+ assert(ParentLC && "We don't start analysis from autosynthesized code");
+ }
+ return LC;
+}
+
+const Stmt *ExplodedNode::getStmtForDiagnostics() const {
+ // We cannot place diagnostics on autosynthesized code.
+ // Put them onto the call site through which we jumped into autosynthesized
+ // code for the first time.
+ const LocationContext *LC = getLocationContext();
+ if (LC->getAnalysisDeclContext()->isBodyAutosynthesized()) {
+ // It must be a stack frame because we only autosynthesize functions.
+ return cast<StackFrameContext>(findTopAutosynthesizedParentContext(LC))
+ ->getCallSite();
+ }
+ // Otherwise, see if the node's program point directly points to a statement.
+ // FIXME: Refactor into a ProgramPoint method?
+ ProgramPoint P = getLocation();
+ if (auto SP = P.getAs<StmtPoint>())
+ return SP->getStmt();
+ if (auto BE = P.getAs<BlockEdge>())
+ return BE->getSrc()->getTerminatorStmt();
+ if (auto CE = P.getAs<CallEnter>())
+ return CE->getCallExpr();
+ if (auto CEE = P.getAs<CallExitEnd>())
+ return CEE->getCalleeContext()->getCallSite();
+ if (auto PIPP = P.getAs<PostInitializer>())
+ return PIPP->getInitializer()->getInit();
+ if (auto CEB = P.getAs<CallExitBegin>())
+ return CEB->getReturnStmt();
+ if (auto FEP = P.getAs<FunctionExitPoint>())
+ return FEP->getStmt();
+
+ return nullptr;
+}
+
+const Stmt *ExplodedNode::getNextStmtForDiagnostics() const {
+ for (const ExplodedNode *N = getFirstSucc(); N; N = N->getFirstSucc()) {
+ if (const Stmt *S = N->getStmtForDiagnostics()) {
+ // Check if the statement is '?' or '&&'/'||'. These are "merges",
+ // not actual statement points.
+ switch (S->getStmtClass()) {
+ case Stmt::ChooseExprClass:
+ case Stmt::BinaryConditionalOperatorClass:
+ case Stmt::ConditionalOperatorClass:
+ continue;
+ case Stmt::BinaryOperatorClass: {
+ BinaryOperatorKind Op = cast<BinaryOperator>(S)->getOpcode();
+ if (Op == BO_LAnd || Op == BO_LOr)
+ continue;
+ break;
+ }
+ default:
+ break;
+ }
+ // We found the statement, so return it.
+ return S;
+ }
+ }
+
+ return nullptr;
+}
+
+const Stmt *ExplodedNode::getPreviousStmtForDiagnostics() const {
+ for (const ExplodedNode *N = getFirstPred(); N; N = N->getFirstPred())
+ if (const Stmt *S = N->getStmtForDiagnostics())
+ return S;
+
+ return nullptr;
+}
+
+const Stmt *ExplodedNode::getCurrentOrPreviousStmtForDiagnostics() const {
+ if (const Stmt *S = getStmtForDiagnostics())
+ return S;
+
+ return getPreviousStmtForDiagnostics();
+}
+
ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
ProgramStateRef State,
bool IsSink,
@@ -313,14 +413,14 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
V = (NodeTy*) getAllocator().Allocate<NodeTy>();
}
- new (V) NodeTy(L, State, IsSink);
+ ++NumNodes;
+ new (V) NodeTy(L, State, NumNodes, IsSink);
if (ReclaimNodeInterval)
ChangedNodes.push_back(V);
// Insert the node into the node set and return it.
Nodes.InsertNode(V, InsertPos);
- ++NumNodes;
if (IsNew) *IsNew = true;
}
@@ -332,9 +432,10 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
ExplodedNode *ExplodedGraph::createUncachedNode(const ProgramPoint &L,
ProgramStateRef State,
+ int64_t Id,
bool IsSink) {
NodeTy *V = (NodeTy *) getAllocator().Allocate<NodeTy>();
- new (V) NodeTy(L, State, IsSink);
+ new (V) NodeTy(L, State, Id, IsSink);
return V;
}
@@ -394,7 +495,8 @@ ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
// Create the corresponding node in the new graph and record the mapping
// from the old node to the new node.
- ExplodedNode *NewN = G->createUncachedNode(N->getLocation(), N->State, N->isSink());
+ ExplodedNode *NewN = G->createUncachedNode(N->getLocation(), N->State,
+ N->getID(), N->isSink());
Pass2[N] = NewN;
// Also record the reverse mapping from the new node to the old node.
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 1fef5b3c1edd..e92e95354f5f 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -977,8 +977,8 @@ void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
Region = makeZeroElementRegion(state, loc::MemRegionVal(Region), varType,
CallOpts.IsArrayCtorOrDtor).getAsRegion();
- VisitCXXDestructor(varType, Region, Dtor.getTriggerStmt(), /*IsBase=*/ false,
- Pred, Dst, CallOpts);
+ VisitCXXDestructor(varType, Region, Dtor.getTriggerStmt(),
+ /*IsBase=*/false, Pred, Dst, CallOpts);
}
void ExprEngine::ProcessDeleteDtor(const CFGDeleteDtor Dtor,
@@ -1036,8 +1036,9 @@ void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy,
Base->isVirtual());
- VisitCXXDestructor(BaseTy, BaseVal.castAs<loc::MemRegionVal>().getRegion(),
- CurDtor->getBody(), /*IsBase=*/ true, Pred, Dst, {});
+ EvalCallOptions CallOpts;
+ VisitCXXDestructor(BaseTy, BaseVal.getAsRegion(), CurDtor->getBody(),
+ /*IsBase=*/true, Pred, Dst, CallOpts);
}
void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
@@ -1048,10 +1049,10 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
const LocationContext *LCtx = Pred->getLocationContext();
const auto *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl());
- Loc ThisVal = getSValBuilder().getCXXThis(CurDtor,
- LCtx->getStackFrame());
- SVal FieldVal =
- State->getLValue(Member, State->getSVal(ThisVal).castAs<Loc>());
+ Loc ThisStorageLoc =
+ getSValBuilder().getCXXThis(CurDtor, LCtx->getStackFrame());
+ Loc ThisLoc = State->getSVal(ThisStorageLoc).castAs<Loc>();
+ SVal FieldVal = State->getLValue(Member, ThisLoc);
// FIXME: We need to run the same destructor on every element of the array.
// This workaround will just run the first destructor (which will still
@@ -1060,8 +1061,8 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
FieldVal = makeZeroElementRegion(State, FieldVal, T,
CallOpts.IsArrayCtorOrDtor);
- VisitCXXDestructor(T, FieldVal.castAs<loc::MemRegionVal>().getRegion(),
- CurDtor->getBody(), /*IsBase=*/false, Pred, Dst, CallOpts);
+ VisitCXXDestructor(T, FieldVal.getAsRegion(), CurDtor->getBody(),
+ /*IsBase=*/false, Pred, Dst, CallOpts);
}
void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
@@ -1109,8 +1110,6 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
EvalCallOptions CallOpts;
CallOpts.IsTemporaryCtorOrDtor = true;
if (!MR) {
- CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true;
-
// If we have no MR, we still need to unwrap the array to avoid destroying
// the whole array at once. Regardless, we'd eventually need to model array
// destructors properly, element-by-element.
@@ -1266,6 +1265,9 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OMPCancelDirectiveClass:
case Stmt::OMPTaskLoopDirectiveClass:
case Stmt::OMPTaskLoopSimdDirectiveClass:
+ case Stmt::OMPMasterTaskLoopDirectiveClass:
+ case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
+ case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
case Stmt::OMPDistributeDirectiveClass:
case Stmt::OMPDistributeParallelForDirectiveClass:
case Stmt::OMPDistributeParallelForSimdDirectiveClass:
@@ -1369,6 +1371,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::CUDAKernelCallExprClass:
case Stmt::OpaqueValueExprClass:
case Stmt::AsTypeExprClass:
+ case Stmt::ConceptSpecializationExprClass:
+ case Stmt::CXXRewrittenBinaryOperatorClass:
// Fall through.
// Cases we intentionally don't evaluate, since they don't need
@@ -3005,9 +3009,13 @@ struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits {
llvm::make_range(BR.EQClasses_begin(), BR.EQClasses_end());
for (const auto &EQ : EQClasses) {
- for (const BugReport &Report : EQ) {
- if (Report.getErrorNode()->getState() == N->getState() &&
- Report.getErrorNode()->getLocation() == N->getLocation())
+ for (const auto &I : EQ.getReports()) {
+ const auto *PR = dyn_cast<PathSensitiveBugReport>(I.get());
+ if (!PR)
+ continue;
+ const ExplodedNode *EN = PR->getErrorNode();
+ if (EN->getState() == N->getState() &&
+ EN->getLocation() == N->getLocation())
return true;
}
}
@@ -3023,22 +3031,16 @@ struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits {
llvm::function_ref<void(const ExplodedNode *)> PreCallback,
llvm::function_ref<void(const ExplodedNode *)> PostCallback,
llvm::function_ref<bool(const ExplodedNode *)> Stop) {
- const ExplodedNode *FirstHiddenNode = N;
- while (FirstHiddenNode->pred_size() == 1 &&
- isNodeHidden(*FirstHiddenNode->pred_begin())) {
- FirstHiddenNode = *FirstHiddenNode->pred_begin();
- }
- const ExplodedNode *OtherNode = FirstHiddenNode;
while (true) {
- PreCallback(OtherNode);
- if (Stop(OtherNode))
+ PreCallback(N);
+ if (Stop(N))
return true;
- if (OtherNode == N)
+ if (N->succ_size() != 1 || !isNodeHidden(N->getFirstSucc()))
break;
- PostCallback(OtherNode);
+ PostCallback(N);
- OtherNode = *OtherNode->succ_begin();
+ N = N->getFirstSucc();
}
return false;
}
@@ -3055,16 +3057,7 @@ struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits {
const unsigned int Space = 1;
ProgramStateRef State = N->getState();
- auto Noop = [](const ExplodedNode*){};
- bool HasReport = traverseHiddenNodes(
- N, Noop, Noop, &nodeHasBugReport);
- bool IsSink = traverseHiddenNodes(
- N, Noop, Noop, [](const ExplodedNode *N) { return N->isSink(); });
-
- Out << "{ \"node_id\": " << N->getID(G) << ", \"pointer\": \""
- << (const void *)N << "\", \"state_id\": " << State->getID()
- << ", \"has_report\": " << (HasReport ? "true" : "false")
- << ", \"is_sink\": " << (IsSink ? "true" : "false")
+ Out << "{ \"state_id\": " << State->getID()
<< ",\\l";
Indent(Out, Space, IsDot) << "\"program_points\": [\\l";
@@ -3077,9 +3070,12 @@ struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits {
OtherNode->getLocation().printJson(Out, /*NL=*/"\\l");
Out << ", \"tag\": ";
if (const ProgramPointTag *Tag = OtherNode->getLocation().getTag())
- Out << '\"' << Tag->getTagDescription() << "\" }";
+ Out << '\"' << Tag->getTagDescription() << "\"";
else
- Out << "null }";
+ Out << "null";
+ Out << ", \"node_id\": " << OtherNode->getID() <<
+ ", \"is_sink\": " << OtherNode->isSink() <<
+ ", \"has_report\": " << nodeHasBugReport(OtherNode) << " }";
},
// Adds a comma and a new-line between each program point.
[&](const ExplodedNode *) { Out << ",\\l"; },
@@ -3088,16 +3084,7 @@ struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits {
Out << "\\l"; // Adds a new-line to the last program point.
Indent(Out, Space, IsDot) << "],\\l";
- bool SameAsAllPredecessors =
- std::all_of(N->pred_begin(), N->pred_end(), [&](const ExplodedNode *P) {
- return P->getState() == State;
- });
-
- if (!SameAsAllPredecessors) {
- State->printDOT(Out, N->getLocationContext(), Space);
- } else {
- Indent(Out, Space, IsDot) << "\"program_state\": null";
- }
+ State->printDOT(Out, N->getLocationContext(), Space);
Out << "\\l}\\l";
return Out.str();
@@ -3132,8 +3119,12 @@ std::string ExprEngine::DumpGraph(bool trim, StringRef Filename) {
// Iterate through the reports and get their nodes.
for (BugReporter::EQClasses_iterator
EI = BR.EQClasses_begin(), EE = BR.EQClasses_end(); EI != EE; ++EI) {
- const auto *N = const_cast<ExplodedNode *>(EI->begin()->getErrorNode());
- if (N) Src.push_back(N);
+ const auto *R =
+ dyn_cast<PathSensitiveBugReport>(EI->getReports()[0].get());
+ if (!R)
+ continue;
+ const auto *N = const_cast<ExplodedNode *>(R->getErrorNode());
+ Src.push_back(N);
}
return DumpGraph(Src, Filename);
} else {
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index f436650fbdd9..02a398c77ac8 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -850,8 +850,7 @@ VisitOffsetOfExpr(const OffsetOfExpr *OOE,
if (OOE->EvaluateAsInt(Result, getContext())) {
APSInt IV = Result.Val.getInt();
assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
- assert(OOE->getType()->isBuiltinType());
- assert(OOE->getType()->getAs<BuiltinType>()->isInteger());
+ assert(OOE->getType()->castAs<BuiltinType>()->isInteger());
assert(IV.isSigned() == OOE->getType()->isSignedIntegerType());
SVal X = svalBuilder.makeIntVal(IV);
B.generateNode(OOE, Pred,
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 1cbd09ea5793..058be985540d 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -323,7 +323,8 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction(
CallEventManager &CEMgr = getStateManager().getCallEventManager();
SVal V = UnknownVal();
auto getArgLoc = [&](CallEventRef<> Caller) -> Optional<SVal> {
- const LocationContext *FutureSFC = Caller->getCalleeStackFrame();
+ const LocationContext *FutureSFC =
+ Caller->getCalleeStackFrame(currBldrCtx->blockCount());
// Return early if we are unable to reliably foresee
// the future stack frame.
if (!FutureSFC)
@@ -342,7 +343,7 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction(
// because this-argument is implemented as a normal argument in
// operator call expressions but not in operator declarations.
const VarRegion *VR = Caller->getParameterLocation(
- *Caller->getAdjustedParameterIndex(Idx));
+ *Caller->getAdjustedParameterIndex(Idx), currBldrCtx->blockCount());
if (!VR)
return None;
@@ -603,7 +604,7 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
bool IsBaseDtor,
ExplodedNode *Pred,
ExplodedNodeSet &Dst,
- const EvalCallOptions &CallOpts) {
+ EvalCallOptions &CallOpts) {
assert(S && "A destructor without a trigger!");
const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef State = Pred->getState();
@@ -611,7 +612,6 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl();
assert(RecordDecl && "Only CXXRecordDecls should have destructors");
const CXXDestructorDecl *DtorDecl = RecordDecl->getDestructor();
-
// FIXME: There should always be a Decl, otherwise the destructor call
// shouldn't have been added to the CFG in the first place.
if (!DtorDecl) {
@@ -625,9 +625,27 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
return;
}
+ if (!Dest) {
+ // We're trying to destroy something that is not a region. This may happen
+ // for a variety of reasons (unknown target region, concrete integer instead
+ // of target region, etc.). The current code makes an attempt to recover.
+ // FIXME: We probably don't really need to recover when we're dealing
+ // with concrete integers specifically.
+ CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true;
+ if (const Expr *E = dyn_cast_or_null<Expr>(S)) {
+ Dest = MRMgr.getCXXTempObjectRegion(E, Pred->getLocationContext());
+ } else {
+ static SimpleProgramPointTag T("ExprEngine", "SkipInvalidDestructor");
+ NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+ Bldr.generateSink(Pred->getLocation().withTag(&T),
+ Pred->getState(), Pred);
+ return;
+ }
+ }
+
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXDestructorCall> Call =
- CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, IsBaseDtor, State, LCtx);
+ CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, IsBaseDtor, State, LCtx);
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
Call->getSourceRange().getBegin(),
@@ -757,7 +775,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
if (!AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
// Invalidate placement args.
// FIXME: Once we figure out how we want allocators to work,
- // we should be using the usual pre-/(default-)eval-/post-call checks here.
+ // we should be using the usual pre-/(default-)eval-/post-call checkers
+ // here.
State = Call->invalidateRegions(blockCount);
if (!State)
return;
@@ -785,9 +804,8 @@ 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.
- if (const SubRegion *NewReg =
- dyn_cast_or_null<SubRegion>(symVal.getAsRegion())) {
- QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
+ if (const auto *NewReg = cast_or_null<SubRegion>(symVal.getAsRegion())) {
+ QualType ObjTy = CNE->getType()->getPointeeType();
const ElementRegion *EleReg =
getStoreManager().GetElementZeroRegion(NewReg, ObjTy);
Result = loc::MemRegionVal(EleReg);
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index b935e3afe34b..345d4d817dea 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -451,9 +451,8 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
// Construct a new stack frame for the callee.
AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
const StackFrameContext *CalleeSFC =
- CalleeADC->getStackFrame(ParentOfCallee, CallE,
- currBldrCtx->getBlock(),
- currStmtIdx);
+ CalleeADC->getStackFrame(ParentOfCallee, CallE, currBldrCtx->getBlock(),
+ currBldrCtx->blockCount(), currStmtIdx);
CallEnter Loc(CallE, CalleeSFC, CurLC);
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 64c42699fcf3..a4918d7179ff 100644
--- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/Stmt.h"
@@ -23,7 +24,6 @@
#include "clang/Rewrite/Core/HTMLRewrite.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/IssueHash.h"
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "llvm/ADT/ArrayRef.h"
@@ -134,17 +134,17 @@ private:
} // namespace
-void ento::createHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
- PathDiagnosticConsumers &C,
- const std::string& prefix,
- const Preprocessor &PP) {
+void ento::createHTMLDiagnosticConsumer(
+ AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C,
+ const std::string &prefix, const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &) {
C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP, true));
}
-void ento::createHTMLSingleFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
- PathDiagnosticConsumers &C,
- const std::string& prefix,
- const Preprocessor &PP) {
+void ento::createHTMLSingleFileDiagnosticConsumer(
+ AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C,
+ const std::string &prefix, const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &) {
C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP, false));
}
@@ -555,8 +555,9 @@ void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R,
os << "\n<!-- FUNCTIONNAME " << declName << " -->\n";
os << "\n<!-- ISSUEHASHCONTENTOFLINEINCONTEXT "
- << GetIssueHash(SMgr, L, D.getCheckName(), D.getBugType(), DeclWithIssue,
- PP.getLangOpts()) << " -->\n";
+ << GetIssueHash(SMgr, L, D.getCheckerName(), D.getBugType(),
+ DeclWithIssue, PP.getLangOpts())
+ << " -->\n";
os << "\n<!-- BUGLINE "
<< LineNumber
@@ -612,7 +613,7 @@ HandlePopUpPieceStartTag(Rewriter &R,
for (const auto &Range : PopUpRanges) {
html::HighlightRange(R, Range.getBegin(), Range.getEnd(), "",
"<table class='variable_popup'><tbody>",
- /*IsTokenRange=*/false);
+ /*IsTokenRange=*/true);
}
}
@@ -644,12 +645,11 @@ static void HandlePopUpPieceEndTag(Rewriter &R,
Out << "</tbody></table></span>";
html::HighlightRange(R, Range.getBegin(), Range.getEnd(),
"<span class='variable'>", Buf.c_str(),
- /*IsTokenRange=*/false);
-
- // Otherwise inject just the new row at the end of the range.
+ /*IsTokenRange=*/true);
} else {
+ // Otherwise inject just the new row at the end of the range.
html::HighlightRange(R, Range.getBegin(), Range.getEnd(), "", Buf.c_str(),
- /*IsTokenRange=*/false);
+ /*IsTokenRange=*/true);
}
}
@@ -658,16 +658,14 @@ void HTMLDiagnostics::RewriteFile(Rewriter &R,
// Process the path.
// Maintain the counts of extra note pieces separately.
unsigned TotalPieces = path.size();
- unsigned TotalNotePieces =
- std::count_if(path.begin(), path.end(),
- [](const std::shared_ptr<PathDiagnosticPiece> &p) {
- return isa<PathDiagnosticNotePiece>(*p);
- });
- unsigned PopUpPieceCount =
- std::count_if(path.begin(), path.end(),
- [](const std::shared_ptr<PathDiagnosticPiece> &p) {
- return isa<PathDiagnosticPopUpPiece>(*p);
- });
+ unsigned TotalNotePieces = std::count_if(
+ path.begin(), path.end(), [](const PathDiagnosticPieceRef &p) {
+ return isa<PathDiagnosticNotePiece>(*p);
+ });
+ unsigned PopUpPieceCount = std::count_if(
+ path.begin(), path.end(), [](const PathDiagnosticPieceRef &p) {
+ return isa<PathDiagnosticPopUpPiece>(*p);
+ });
unsigned TotalRegularPieces = TotalPieces - TotalNotePieces - PopUpPieceCount;
unsigned NumRegularPieces = TotalRegularPieces;
diff --git a/lib/StaticAnalyzer/Core/LoopUnrolling.cpp b/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
index 9838249ae82c..1a09a521f116 100644
--- a/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ b/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -165,7 +165,9 @@ static bool isPossiblyEscaped(const VarDecl *VD, ExplodedNode *N) {
return true;
while (!N->pred_empty()) {
- const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ // FIXME: getStmtForDiagnostics() does nasty things in order to provide
+ // a valid statement for body farms, do we need this behavior here?
+ const Stmt *S = N->getStmtForDiagnostics();
if (!S) {
N = N->getFirstPred();
continue;
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index f763701af7fb..a10d7e69ad7e 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -506,7 +506,7 @@ void ElementRegion::dumpToStream(raw_ostream &os) const {
}
void FieldRegion::dumpToStream(raw_ostream &os) const {
- os << superRegion << "->" << *getDecl();
+ os << superRegion << "." << *getDecl();
}
void ObjCIvarRegion::dumpToStream(raw_ostream &os) const {
@@ -1075,7 +1075,7 @@ MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *RD,
const SubRegion *Super,
bool IsVirtual) {
if (isa<TypedValueRegion>(Super)) {
- assert(isValidBaseClass(RD, dyn_cast<TypedValueRegion>(Super), IsVirtual));
+ assert(isValidBaseClass(RD, cast<TypedValueRegion>(Super), IsVirtual));
(void)&isValidBaseClass;
if (IsVirtual) {
@@ -1426,6 +1426,7 @@ static RegionOffset calculateOffset(const MemRegion *R) {
case MemRegion::FieldRegionKind: {
const auto *FR = cast<FieldRegion>(R);
R = FR->getSuperRegion();
+ assert(R);
const RecordDecl *RD = FR->getDecl()->getParent();
if (RD->isUnion() || !RD->isCompleteDefinition()) {
diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index 838751279297..3a3942a8301b 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -10,20 +10,22 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/PlistSupport.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
+#include "clang/CrossTU/CrossTranslationUnit.h"
+#include "clang/Frontend/ASTUnit.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/TokenConcatenation.h"
#include "clang/Rewrite/Core/HTMLRewrite.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/IssueHash.h"
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
-#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Casting.h"
using namespace clang;
@@ -39,12 +41,13 @@ namespace {
class PlistDiagnostics : public PathDiagnosticConsumer {
const std::string OutputFile;
const Preprocessor &PP;
+ const cross_tu::CrossTranslationUnitContext &CTU;
AnalyzerOptions &AnOpts;
const bool SupportsCrossFileDiagnostics;
public:
- PlistDiagnostics(AnalyzerOptions &AnalyzerOpts,
- const std::string& prefix,
+ PlistDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string &prefix,
const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &CTU,
bool supportsMultipleFiles);
~PlistDiagnostics() override {}
@@ -73,12 +76,14 @@ class PlistPrinter {
const FIDMap& FM;
AnalyzerOptions &AnOpts;
const Preprocessor &PP;
+ const cross_tu::CrossTranslationUnitContext &CTU;
llvm::SmallVector<const PathDiagnosticMacroPiece *, 0> MacroPieces;
public:
PlistPrinter(const FIDMap& FM, AnalyzerOptions &AnOpts,
- const Preprocessor &PP)
- : FM(FM), AnOpts(AnOpts), PP(PP) {
+ const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &CTU)
+ : FM(FM), AnOpts(AnOpts), PP(PP), CTU(CTU) {
}
void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P) {
@@ -129,6 +134,7 @@ private:
void EmitRanges(raw_ostream &o, const ArrayRef<SourceRange> Ranges,
unsigned indent);
void EmitMessage(raw_ostream &o, StringRef Message, unsigned indent);
+ void EmitFixits(raw_ostream &o, ArrayRef<FixItHint> fixits, unsigned indent);
void ReportControlFlow(raw_ostream &o,
const PathDiagnosticControlFlowPiece& P,
@@ -160,8 +166,8 @@ struct ExpansionInfo {
} // end of anonymous namespace
static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM,
- AnalyzerOptions &AnOpts,
- const Preprocessor &PP,
+ AnalyzerOptions &AnOpts, const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &CTU,
const PathPieces &Path);
/// Print coverage information to output stream {@code o}.
@@ -172,8 +178,9 @@ static void printCoverage(const PathDiagnostic *D,
FIDMap &FM,
llvm::raw_fd_ostream &o);
-static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc,
- const Preprocessor &PP);
+static ExpansionInfo
+getExpandedMacro(SourceLocation MacroLoc, const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &CTU);
//===----------------------------------------------------------------------===//
// Methods of PlistPrinter.
@@ -216,6 +223,33 @@ void PlistPrinter::EmitMessage(raw_ostream &o, StringRef Message,
EmitString(o, Message) << '\n';
}
+void PlistPrinter::EmitFixits(raw_ostream &o, ArrayRef<FixItHint> fixits,
+ unsigned indent) {
+ if (fixits.size() == 0)
+ return;
+
+ const SourceManager &SM = PP.getSourceManager();
+ const LangOptions &LangOpts = PP.getLangOpts();
+
+ Indent(o, indent) << "<key>fixits</key>\n";
+ Indent(o, indent) << "<array>\n";
+ for (const auto &fixit : fixits) {
+ assert(!fixit.isNull());
+ // FIXME: Add support for InsertFromRange and BeforePreviousInsertion.
+ assert(!fixit.InsertFromRange.isValid() && "Not implemented yet!");
+ assert(!fixit.BeforePreviousInsertions && "Not implemented yet!");
+ Indent(o, indent) << " <dict>\n";
+ Indent(o, indent) << " <key>remove_range</key>\n";
+ EmitRange(o, SM, Lexer::getAsCharRange(fixit.RemoveRange, SM, LangOpts),
+ FM, indent + 2);
+ Indent(o, indent) << " <key>insert_string</key>";
+ EmitString(o, fixit.CodeToInsert);
+ o << "\n";
+ Indent(o, indent) << " </dict>\n";
+ }
+ Indent(o, indent) << "</array>\n";
+}
+
void PlistPrinter::ReportControlFlow(raw_ostream &o,
const PathDiagnosticControlFlowPiece& P,
unsigned indent) {
@@ -266,6 +300,9 @@ void PlistPrinter::ReportControlFlow(raw_ostream &o,
EmitString(o, s) << '\n';
}
+ assert(P.getFixits().size() == 0 &&
+ "Fixits on constrol flow pieces are not implemented yet!");
+
--indent;
Indent(o, indent) << "</dict>\n";
}
@@ -302,6 +339,9 @@ void PlistPrinter::ReportEvent(raw_ostream &o, const PathDiagnosticEventPiece& P
// Output the text.
EmitMessage(o, P.getString(), indent);
+ // Output the fixits.
+ EmitFixits(o, P.getFixits(), indent);
+
// Finish up.
--indent;
Indent(o, indent); o << "</dict>\n";
@@ -329,6 +369,9 @@ void PlistPrinter::ReportCall(raw_ostream &o, const PathDiagnosticCallPiece &P,
if (auto callExit = P.getCallExitEvent())
ReportPiece(o, *callExit, indent, depth, /*includeControlFlow*/ true);
+
+ assert(P.getFixits().size() == 0 &&
+ "Fixits on call pieces are not implemented yet!");
}
void PlistPrinter::ReportMacroSubPieces(raw_ostream &o,
@@ -341,13 +384,16 @@ void PlistPrinter::ReportMacroSubPieces(raw_ostream &o,
I != E; ++I) {
ReportPiece(o, **I, indent, depth, /*includeControlFlow*/ false);
}
+
+ assert(P.getFixits().size() == 0 &&
+ "Fixits on constrol flow pieces are not implemented yet!");
}
void PlistPrinter::ReportMacroExpansions(raw_ostream &o, unsigned indent) {
for (const PathDiagnosticMacroPiece *P : MacroPieces) {
const SourceManager &SM = PP.getSourceManager();
- ExpansionInfo EI = getExpandedMacro(P->getLocation().asLocation(), PP);
+ ExpansionInfo EI = getExpandedMacro(P->getLocation().asLocation(), PP, CTU);
Indent(o, indent) << "<dict>\n";
++indent;
@@ -398,6 +444,9 @@ void PlistPrinter::ReportNote(raw_ostream &o, const PathDiagnosticNotePiece& P,
// Output the text.
EmitMessage(o, P.getString(), indent);
+ // Output the fixits.
+ EmitFixits(o, P.getFixits(), indent);
+
// Finish up.
--indent;
Indent(o, indent); o << "</dict>\n";
@@ -426,6 +475,9 @@ void PlistPrinter::ReportPopUp(raw_ostream &o,
// Output the text.
EmitMessage(o, P.getString(), indent);
+ assert(P.getFixits().size() == 0 &&
+ "Fixits on pop-up pieces are not implemented yet!");
+
// Finish up.
--indent;
Indent(o, indent) << "</dict>\n";
@@ -469,20 +521,20 @@ static void printCoverage(const PathDiagnostic *D,
}
static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM,
- AnalyzerOptions &AnOpts,
- const Preprocessor &PP,
+ AnalyzerOptions &AnOpts, const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &CTU,
const PathPieces &Path) {
- PlistPrinter Printer(FM, AnOpts, PP);
- assert(std::is_partitioned(
- Path.begin(), Path.end(),
- [](const std::shared_ptr<PathDiagnosticPiece> &E)
- { return E->getKind() == PathDiagnosticPiece::Note; }) &&
+ PlistPrinter Printer(FM, AnOpts, PP, CTU);
+ assert(std::is_partitioned(Path.begin(), Path.end(),
+ [](const PathDiagnosticPieceRef &E) {
+ return E->getKind() == PathDiagnosticPiece::Note;
+ }) &&
"PathDiagnostic is not partitioned so that notes precede the rest");
PathPieces::const_iterator FirstNonNote = std::partition_point(
- Path.begin(), Path.end(),
- [](const std::shared_ptr<PathDiagnosticPiece> &E)
- { return E->getKind() == PathDiagnosticPiece::Note; });
+ Path.begin(), Path.end(), [](const PathDiagnosticPieceRef &E) {
+ return E->getKind() == PathDiagnosticPiece::Note;
+ });
PathPieces::const_iterator I = Path.begin();
@@ -518,26 +570,29 @@ static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM,
// Methods of PlistDiagnostics.
//===----------------------------------------------------------------------===//
-PlistDiagnostics::PlistDiagnostics(AnalyzerOptions &AnalyzerOpts,
- const std::string& output,
- const Preprocessor &PP,
- bool supportsMultipleFiles)
- : OutputFile(output), PP(PP), AnOpts(AnalyzerOpts),
- SupportsCrossFileDiagnostics(supportsMultipleFiles) {}
-
-void ento::createPlistDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
- PathDiagnosticConsumers &C,
- const std::string& s,
- const Preprocessor &PP) {
- C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP,
+PlistDiagnostics::PlistDiagnostics(
+ AnalyzerOptions &AnalyzerOpts, const std::string &output,
+ const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU,
+ bool supportsMultipleFiles)
+ : OutputFile(output), PP(PP), CTU(CTU), AnOpts(AnalyzerOpts),
+ SupportsCrossFileDiagnostics(supportsMultipleFiles) {
+ // FIXME: Will be used by a later planned change.
+ (void)this->CTU;
+}
+
+void ento::createPlistDiagnosticConsumer(
+ AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C,
+ const std::string &s, const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &CTU) {
+ C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP, CTU,
/*supportsMultipleFiles*/ false));
}
-void ento::createPlistMultiFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
- PathDiagnosticConsumers &C,
- const std::string &s,
- const Preprocessor &PP) {
- C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP,
+void ento::createPlistMultiFileDiagnosticConsumer(
+ AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C,
+ const std::string &s, const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &CTU) {
+ C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP, CTU,
/*supportsMultipleFiles*/ true));
}
void PlistDiagnostics::FlushDiagnosticsImpl(
@@ -590,7 +645,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
// Open the file.
std::error_code EC;
- llvm::raw_fd_ostream o(OutputFile, EC, llvm::sys::fs::F_Text);
+ llvm::raw_fd_ostream o(OutputFile, EC, llvm::sys::fs::OF_Text);
if (EC) {
llvm::errs() << "warning: could not create file: " << EC.message() << '\n';
return;
@@ -614,7 +669,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
o << " <dict>\n";
const PathDiagnostic *D = *DI;
- printBugPath(o, FM, AnOpts, PP, D->path);
+ printBugPath(o, FM, AnOpts, PP, CTU, D->path);
// Output the bug type and bug category.
o << " <key>description</key>";
@@ -624,7 +679,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
o << " <key>type</key>";
EmitString(o, D->getBugType()) << '\n';
o << " <key>check_name</key>";
- EmitString(o, D->getCheckName()) << '\n';
+ EmitString(o, D->getCheckerName()) << '\n';
o << " <!-- This hash is experimental and going to change! -->\n";
o << " <key>issue_hash_content_of_line_in_context</key>";
@@ -634,7 +689,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
: D->getLocation().asLocation()),
SM);
const Decl *DeclWithIssue = D->getDeclWithIssue();
- EmitString(o, GetIssueHash(SM, L, D->getCheckName(), D->getBugType(),
+ EmitString(o, GetIssueHash(SM, L, D->getCheckerName(), D->getBugType(),
DeclWithIssue, LangOpts))
<< '\n';
@@ -867,17 +922,23 @@ static const MacroInfo *getMacroInfoForLocation(const Preprocessor &PP,
// Definitions of helper functions and methods for expanding macros.
//===----------------------------------------------------------------------===//
-static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc,
- const Preprocessor &PP) {
+static ExpansionInfo
+getExpandedMacro(SourceLocation MacroLoc, const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &CTU) {
+
+ const Preprocessor *PPToUse = &PP;
+ if (auto LocAndUnit = CTU.getImportedFromSourceLocation(MacroLoc)) {
+ MacroLoc = LocAndUnit->first;
+ PPToUse = &LocAndUnit->second->getPreprocessor();
+ }
llvm::SmallString<200> ExpansionBuf;
llvm::raw_svector_ostream OS(ExpansionBuf);
- TokenPrinter Printer(OS, PP);
+ TokenPrinter Printer(OS, *PPToUse);
llvm::SmallPtrSet<IdentifierInfo*, 8> AlreadyProcessedTokens;
- std::string MacroName =
- getMacroNameAndPrintExpansion(Printer, MacroLoc, PP, MacroArgMap{},
- AlreadyProcessedTokens);
+ std::string MacroName = getMacroNameAndPrintExpansion(
+ Printer, MacroLoc, *PPToUse, MacroArgMap{}, AlreadyProcessedTokens);
return { MacroName, OS.str() };
}
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index a1ca0b1b84bf..f50d82de3b28 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -15,7 +15,7 @@
#include "clang/Basic/JsonSupport.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 64724227395d..9752a0e22832 100644
--- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -330,7 +330,7 @@ private:
std::unique_ptr<ConstraintManager>
ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine *Eng) {
- return llvm::make_unique<RangeConstraintManager>(Eng, StMgr.getSValBuilder());
+ return std::make_unique<RangeConstraintManager>(Eng, StMgr.getSValBuilder());
}
bool RangeConstraintManager::canReasonAbout(SVal X) const {
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index d2aea1fd92dd..5d2ef59e2d66 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -108,7 +108,7 @@ public:
Data == X.Data;
}
- void dump() const;
+ LLVM_DUMP_METHOD void dump() const;
};
} // end anonymous namespace
@@ -135,7 +135,9 @@ static inline raw_ostream &operator<<(raw_ostream &Out, BindingKey K) {
} // namespace llvm
-LLVM_DUMP_METHOD void BindingKey::dump() const { llvm::errs() << *this; }
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+void BindingKey::dump() const { llvm::errs() << *this; }
+#endif
//===----------------------------------------------------------------------===//
// Actual Store type.
@@ -153,28 +155,42 @@ class RegionBindingsRef : public llvm::ImmutableMapRef<const MemRegion *,
ClusterBindings> {
ClusterBindings::Factory *CBFactory;
+ // This flag indicates whether the current bindings are within the analysis
+ // that has started from main(). It affects how we perform loads from
+ // global variables that have initializers: if we have observed the
+ // program execution from the start and we know that these variables
+ // have not been overwritten yet, we can be sure that their initializers
+ // are still relevant. This flag never gets changed when the bindings are
+ // updated, so it could potentially be moved into RegionStoreManager
+ // (as if it's the same bindings but a different loading procedure)
+ // however that would have made the manager needlessly stateful.
+ bool IsMainAnalysis;
+
public:
typedef llvm::ImmutableMapRef<const MemRegion *, ClusterBindings>
ParentTy;
RegionBindingsRef(ClusterBindings::Factory &CBFactory,
const RegionBindings::TreeTy *T,
- RegionBindings::TreeTy::Factory *F)
+ RegionBindings::TreeTy::Factory *F,
+ bool IsMainAnalysis)
: llvm::ImmutableMapRef<const MemRegion *, ClusterBindings>(T, F),
- CBFactory(&CBFactory) {}
+ CBFactory(&CBFactory), IsMainAnalysis(IsMainAnalysis) {}
- RegionBindingsRef(const ParentTy &P, ClusterBindings::Factory &CBFactory)
+ RegionBindingsRef(const ParentTy &P,
+ ClusterBindings::Factory &CBFactory,
+ bool IsMainAnalysis)
: llvm::ImmutableMapRef<const MemRegion *, ClusterBindings>(P),
- CBFactory(&CBFactory) {}
+ CBFactory(&CBFactory), IsMainAnalysis(IsMainAnalysis) {}
RegionBindingsRef add(key_type_ref K, data_type_ref D) const {
return RegionBindingsRef(static_cast<const ParentTy *>(this)->add(K, D),
- *CBFactory);
+ *CBFactory, IsMainAnalysis);
}
RegionBindingsRef remove(key_type_ref K) const {
return RegionBindingsRef(static_cast<const ParentTy *>(this)->remove(K),
- *CBFactory);
+ *CBFactory, IsMainAnalysis);
}
RegionBindingsRef addBinding(BindingKey K, SVal V) const;
@@ -204,7 +220,13 @@ public:
/// Return the internal tree as a Store.
Store asStore() const {
- return asImmutableMap().getRootWithoutRetain();
+ llvm::PointerIntPair<Store, 1, bool> Ptr = {
+ asImmutableMap().getRootWithoutRetain(), IsMainAnalysis};
+ return reinterpret_cast<Store>(Ptr.getOpaqueValue());
+ }
+
+ bool isMainAnalysis() const {
+ return IsMainAnalysis;
}
void printJson(raw_ostream &Out, const char *NL = "\n",
@@ -379,8 +401,15 @@ public:
/// casts from arrays to pointers.
SVal ArrayToPointer(Loc Array, QualType ElementTy) override;
+ /// Creates the Store that correctly represents memory contents before
+ /// the beginning of the analysis of the given top-level stack frame.
StoreRef getInitialStore(const LocationContext *InitLoc) override {
- return StoreRef(RBFactory.getEmptyMap().getRootWithoutRetain(), *this);
+ bool IsMainAnalysis = false;
+ if (const auto *FD = dyn_cast<FunctionDecl>(InitLoc->getDecl()))
+ IsMainAnalysis = FD->isMain() && !Ctx.getLangOpts().CPlusPlus;
+ return StoreRef(RegionBindingsRef(
+ RegionBindingsRef::ParentTy(RBFactory.getEmptyMap(), RBFactory),
+ CBFactory, IsMainAnalysis).asStore(), *this);
}
//===-------------------------------------------------------------------===//
@@ -606,9 +635,13 @@ public: // Part of public interface to class.
//===------------------------------------------------------------------===//
RegionBindingsRef getRegionBindings(Store store) const {
- return RegionBindingsRef(CBFactory,
- static_cast<const RegionBindings::TreeTy*>(store),
- RBFactory.getTreeFactory());
+ llvm::PointerIntPair<Store, 1, bool> Ptr;
+ Ptr.setFromOpaqueValue(const_cast<void *>(store));
+ return RegionBindingsRef(
+ CBFactory,
+ static_cast<const RegionBindings::TreeTy *>(Ptr.getPointer()),
+ RBFactory.getTreeFactory(),
+ Ptr.getInt());
}
void printJson(raw_ostream &Out, Store S, const char *NL = "\n",
@@ -642,14 +675,14 @@ public: // Part of public interface to class.
std::unique_ptr<StoreManager>
ento::CreateRegionStoreManager(ProgramStateManager &StMgr) {
RegionStoreFeatures F = maximal_features_tag();
- return llvm::make_unique<RegionStoreManager>(StMgr, F);
+ return std::make_unique<RegionStoreManager>(StMgr, F);
}
std::unique_ptr<StoreManager>
ento::CreateFieldsOnlyRegionStoreManager(ProgramStateManager &StMgr) {
RegionStoreFeatures F = minimal_features_tag();
F.enableFields(true);
- return llvm::make_unique<RegionStoreManager>(StMgr, F);
+ return std::make_unique<RegionStoreManager>(StMgr, F);
}
@@ -1669,10 +1702,12 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
return svalBuilder.makeIntVal(c, T);
}
} else if (const VarRegion *VR = dyn_cast<VarRegion>(superR)) {
- // Check if the containing array is const and has an initialized value.
+ // Check if the containing array has an initialized value that we can trust.
+ // We can trust a const value or a value of a global initializer in main().
const VarDecl *VD = VR->getDecl();
- // Either the array or the array element has to be const.
- if (VD->getType().isConstQualified() || R->getElementType().isConstQualified()) {
+ if (VD->getType().isConstQualified() ||
+ R->getElementType().isConstQualified() ||
+ (B.isMainAnalysis() && VD->hasGlobalStorage())) {
if (const Expr *Init = VD->getAnyInitializer()) {
if (const auto *InitList = dyn_cast<InitListExpr>(Init)) {
// The array index has to be known.
@@ -1761,8 +1796,11 @@ SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
const VarDecl *VD = VR->getDecl();
QualType RecordVarTy = VD->getType();
unsigned Index = FD->getFieldIndex();
- // Either the record variable or the field has to be const qualified.
- if (RecordVarTy.isConstQualified() || Ty.isConstQualified())
+ // Either the record variable or the field has an initializer that we can
+ // trust. We trust initializers of constants and, additionally, respect
+ // initializers of globals when analyzing main().
+ if (RecordVarTy.isConstQualified() || Ty.isConstQualified() ||
+ (B.isMainAnalysis() && VD->hasGlobalStorage()))
if (const Expr *Init = VD->getAnyInitializer())
if (const auto *InitList = dyn_cast<InitListExpr>(Init)) {
if (Index < InitList->getNumInits()) {
@@ -1980,6 +2018,12 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
if (isa<GlobalsSpaceRegion>(MS)) {
QualType T = VD->getType();
+ // If we're in main(), then global initializers have not become stale yet.
+ if (B.isMainAnalysis())
+ if (const Expr *Init = VD->getAnyInitializer())
+ if (Optional<SVal> V = svalBuilder.getConstantVal(Init))
+ return *V;
+
// Function-scoped static variables are default-initialized to 0; if they
// have an initializer, it would have been processed by now.
// FIXME: This is only true when we're starting analysis from main().
@@ -2247,8 +2291,7 @@ RegionBindingsRef RegionStoreManager::bindVector(RegionBindingsConstRef B,
const TypedValueRegion* R,
SVal V) {
QualType T = R->getValueType();
- assert(T->isVectorType());
- const VectorType *VT = T->getAs<VectorType>(); // Use getAs for typedefs.
+ const VectorType *VT = T->castAs<VectorType>(); // Use castAs for typedefs.
// Handle lazy compound values and symbolic values.
if (V.getAs<nonloc::LazyCompoundVal>() || V.getAs<nonloc::SymbolVal>())
@@ -2333,7 +2376,7 @@ RegionBindingsRef RegionStoreManager::bindStruct(RegionBindingsConstRef B,
QualType T = R->getValueType();
assert(T->isStructureOrClassType());
- const RecordType* RT = T->getAs<RecordType>();
+ const RecordType* RT = T->castAs<RecordType>();
const RecordDecl *RD = RT->getDecl();
if (!RD->isCompleteDefinition())
diff --git a/lib/StaticAnalyzer/Core/SMTConstraintManager.cpp b/lib/StaticAnalyzer/Core/SMTConstraintManager.cpp
index d5c14351d330..6ad12ca0a688 100644
--- a/lib/StaticAnalyzer/Core/SMTConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/SMTConstraintManager.cpp
@@ -14,5 +14,5 @@ using namespace ento;
std::unique_ptr<ConstraintManager>
ento::CreateZ3ConstraintManager(ProgramStateManager &StMgr, SubEngine *Eng) {
- return llvm::make_unique<SMTConstraintManager>(Eng, StMgr.getSValBuilder());
+ return std::make_unique<SMTConstraintManager>(Eng, StMgr.getSValBuilder());
}
diff --git a/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp b/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp
index d1faf3f4dea9..190ab7e21dbc 100644
--- a/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp
@@ -10,10 +10,10 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Basic/Version.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h"
@@ -43,10 +43,10 @@ public:
};
} // end anonymous namespace
-void ento::createSarifDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
- PathDiagnosticConsumers &C,
- const std::string &Output,
- const Preprocessor &) {
+void ento::createSarifDiagnosticConsumer(
+ AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C,
+ const std::string &Output, const Preprocessor &,
+ const cross_tu::CrossTranslationUnitContext &) {
C.push_back(new SarifDiagnostics(AnalyzerOpts, Output));
}
@@ -106,26 +106,26 @@ static std::string fileNameToURI(StringRef Filename) {
return Ret.str().str();
}
-static json::Object createFileLocation(const FileEntry &FE) {
+static json::Object createArtifactLocation(const FileEntry &FE) {
return json::Object{{"uri", fileNameToURI(getFileName(FE))}};
}
-static json::Object createFile(const FileEntry &FE) {
- return json::Object{{"fileLocation", createFileLocation(FE)},
+static json::Object createArtifact(const FileEntry &FE) {
+ return json::Object{{"location", createArtifactLocation(FE)},
{"roles", json::Array{"resultFile"}},
{"length", FE.getSize()},
{"mimeType", "text/plain"}};
}
-static json::Object createFileLocation(const FileEntry &FE,
- json::Array &Files) {
+static json::Object createArtifactLocation(const FileEntry &FE,
+ json::Array &Artifacts) {
std::string FileURI = fileNameToURI(getFileName(FE));
- // See if the Files array contains this URI already. If it does not, create
- // a new file object to add to the array.
- auto I = llvm::find_if(Files, [&](const json::Value &File) {
+ // See if the Artifacts array contains this URI already. If it does not,
+ // create a new artifact object to add to the array.
+ auto I = llvm::find_if(Artifacts, [&](const json::Value &File) {
if (const json::Object *Obj = File.getAsObject()) {
- if (const json::Object *FileLoc = Obj->getObject("fileLocation")) {
+ if (const json::Object *FileLoc = Obj->getObject("location")) {
Optional<StringRef> URI = FileLoc->getString("uri");
return URI && URI->equals(FileURI);
}
@@ -133,28 +133,35 @@ static json::Object createFileLocation(const FileEntry &FE,
return false;
});
- // Calculate the index within the file location array so it can be stored in
+ // Calculate the index within the artifact array so it can be stored in
// the JSON object.
- auto Index = static_cast<unsigned>(std::distance(Files.begin(), I));
- if (I == Files.end())
- Files.push_back(createFile(FE));
+ auto Index = static_cast<unsigned>(std::distance(Artifacts.begin(), I));
+ if (I == Artifacts.end())
+ Artifacts.push_back(createArtifact(FE));
- return json::Object{{"uri", FileURI}, {"fileIndex", Index}};
+ return json::Object{{"uri", FileURI}, {"index", Index}};
}
static json::Object createTextRegion(SourceRange R, const SourceManager &SM) {
- return json::Object{
+ json::Object Region{
{"startLine", SM.getExpansionLineNumber(R.getBegin())},
- {"endLine", SM.getExpansionLineNumber(R.getEnd())},
{"startColumn", SM.getExpansionColumnNumber(R.getBegin())},
- {"endColumn", SM.getExpansionColumnNumber(R.getEnd())}};
+ };
+ if (R.getBegin() == R.getEnd()) {
+ Region["endColumn"] = SM.getExpansionColumnNumber(R.getBegin());
+ } else {
+ Region["endLine"] = SM.getExpansionLineNumber(R.getEnd());
+ Region["endColumn"] = SM.getExpansionColumnNumber(R.getEnd()) + 1;
+ }
+ return Region;
}
static json::Object createPhysicalLocation(SourceRange R, const FileEntry &FE,
const SourceManager &SMgr,
- json::Array &Files) {
- return json::Object{{{"fileLocation", createFileLocation(FE, Files)},
- {"region", createTextRegion(R, SMgr)}}};
+ json::Array &Artifacts) {
+ return json::Object{
+ {{"artifactLocation", createArtifactLocation(FE, Artifacts)},
+ {"region", createTextRegion(R, SMgr)}}};
}
enum class Importance { Important, Essential, Unimportant };
@@ -207,15 +214,16 @@ static Importance calculateImportance(const PathDiagnosticPiece &Piece) {
}
static json::Object createThreadFlow(const PathPieces &Pieces,
- json::Array &Files) {
+ json::Array &Artifacts) {
const SourceManager &SMgr = Pieces.front()->getLocation().getManager();
json::Array Locations;
for (const auto &Piece : Pieces) {
const PathDiagnosticLocation &P = Piece->getLocation();
Locations.push_back(createThreadFlowLocation(
- createLocation(createPhysicalLocation(P.asRange(),
- *P.asLocation().getFileEntry(),
- SMgr, Files),
+ createLocation(createPhysicalLocation(
+ P.asRange(),
+ *P.asLocation().getExpansionLoc().getFileEntry(),
+ SMgr, Artifacts),
Piece->getString()),
calculateImportance(*Piece)));
}
@@ -223,35 +231,30 @@ static json::Object createThreadFlow(const PathPieces &Pieces,
}
static json::Object createCodeFlow(const PathPieces &Pieces,
- json::Array &Files) {
+ json::Array &Artifacts) {
return json::Object{
- {"threadFlows", json::Array{createThreadFlow(Pieces, Files)}}};
+ {"threadFlows", json::Array{createThreadFlow(Pieces, Artifacts)}}};
}
-static json::Object createTool() {
- return json::Object{{"name", "clang"},
- {"fullName", "clang static analyzer"},
- {"language", "en-US"},
- {"version", getClangFullVersion()}};
-}
-
-static json::Object createResult(const PathDiagnostic &Diag, json::Array &Files,
+static json::Object createResult(const PathDiagnostic &Diag,
+ json::Array &Artifacts,
const StringMap<unsigned> &RuleMapping) {
const PathPieces &Path = Diag.path.flatten(false);
const SourceManager &SMgr = Path.front()->getLocation().getManager();
- auto Iter = RuleMapping.find(Diag.getCheckName());
+ auto Iter = RuleMapping.find(Diag.getCheckerName());
assert(Iter != RuleMapping.end() && "Rule ID is not in the array index map?");
return json::Object{
{"message", createMessage(Diag.getVerboseDescription())},
- {"codeFlows", json::Array{createCodeFlow(Path, Files)}},
+ {"codeFlows", json::Array{createCodeFlow(Path, Artifacts)}},
{"locations",
json::Array{createLocation(createPhysicalLocation(
Diag.getLocation().asRange(),
- *Diag.getLocation().asLocation().getFileEntry(), SMgr, Files))}},
+ *Diag.getLocation().asLocation().getExpansionLoc().getFileEntry(),
+ SMgr, Artifacts))}},
{"ruleIndex", Iter->getValue()},
- {"ruleId", Diag.getCheckName()}};
+ {"ruleId", Diag.getCheckerName()}};
}
static StringRef getRuleDescription(StringRef CheckName) {
@@ -277,10 +280,10 @@ static StringRef getRuleHelpURIStr(StringRef CheckName) {
}
static json::Object createRule(const PathDiagnostic &Diag) {
- StringRef CheckName = Diag.getCheckName();
+ StringRef CheckName = Diag.getCheckerName();
json::Object Ret{
{"fullDescription", createMessage(getRuleDescription(CheckName))},
- {"name", createMessage(CheckName)},
+ {"name", CheckName},
{"id", CheckName}};
std::string RuleURI = getRuleHelpURIStr(CheckName);
@@ -296,7 +299,7 @@ static json::Array createRules(std::vector<const PathDiagnostic *> &Diags,
llvm::StringSet<> Seen;
llvm::for_each(Diags, [&](const PathDiagnostic *D) {
- StringRef RuleID = D->getCheckName();
+ StringRef RuleID = D->getCheckerName();
std::pair<llvm::StringSet<>::iterator, bool> P = Seen.insert(RuleID);
if (P.second) {
RuleMapping[RuleID] = Rules.size(); // Maps RuleID to an Array Index.
@@ -307,24 +310,28 @@ static json::Array createRules(std::vector<const PathDiagnostic *> &Diags,
return Rules;
}
-static json::Object createResources(std::vector<const PathDiagnostic *> &Diags,
- StringMap<unsigned> &RuleMapping) {
- return json::Object{{"rules", createRules(Diags, RuleMapping)}};
+static json::Object createTool(std::vector<const PathDiagnostic *> &Diags,
+ StringMap<unsigned> &RuleMapping) {
+ return json::Object{
+ {"driver", json::Object{{"name", "clang"},
+ {"fullName", "clang static analyzer"},
+ {"language", "en-US"},
+ {"version", getClangFullVersion()},
+ {"rules", createRules(Diags, RuleMapping)}}}};
}
static json::Object createRun(std::vector<const PathDiagnostic *> &Diags) {
- json::Array Results, Files;
+ json::Array Results, Artifacts;
StringMap<unsigned> RuleMapping;
- json::Object Resources = createResources(Diags, RuleMapping);
+ json::Object Tool = createTool(Diags, RuleMapping);
llvm::for_each(Diags, [&](const PathDiagnostic *D) {
- Results.push_back(createResult(*D, Files, RuleMapping));
+ Results.push_back(createResult(*D, Artifacts, RuleMapping));
});
- return json::Object{{"tool", createTool()},
- {"resources", std::move(Resources)},
+ return json::Object{{"tool", std::move(Tool)},
{"results", std::move(Results)},
- {"files", std::move(Files)}};
+ {"artifacts", std::move(Artifacts)}};
}
void SarifDiagnostics::FlushDiagnosticsImpl(
@@ -335,15 +342,15 @@ void SarifDiagnostics::FlushDiagnosticsImpl(
// file can become large very quickly, so decoding into JSON to append a run
// may be an expensive operation.
std::error_code EC;
- llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
+ llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::OF_Text);
if (EC) {
llvm::errs() << "warning: could not create file: " << EC.message() << '\n';
return;
}
json::Object Sarif{
{"$schema",
- "http://json.schemastore.org/sarif-2.0.0-csd.2.beta.2018-11-28"},
- {"version", "2.0.0-csd.2.beta.2018-11-28"},
+ "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"},
+ {"version", "2.1.0"},
{"runs", json::Array{createRun(Diags)}}};
OS << llvm::formatv("{0:2}\n", json::Value(std::move(Sarif)));
}
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index 3cf616161c66..b4ab6877726c 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -52,7 +52,7 @@ StoreRef StoreManager::enterStackFrame(Store OldStore,
Call.getInitialStackFrameContents(LCtx, InitialBindings);
for (const auto &I : InitialBindings)
- Store = Bind(Store.getStore(), I.first, I.second);
+ Store = Bind(Store.getStore(), I.first.castAs<Loc>(), I.second);
return Store;
}
diff --git a/lib/StaticAnalyzer/Core/WorkList.cpp b/lib/StaticAnalyzer/Core/WorkList.cpp
index 129d1720395e..348552ba73a9 100644
--- a/lib/StaticAnalyzer/Core/WorkList.cpp
+++ b/lib/StaticAnalyzer/Core/WorkList.cpp
@@ -79,11 +79,11 @@ public:
WorkList::~WorkList() = default;
std::unique_ptr<WorkList> WorkList::makeDFS() {
- return llvm::make_unique<DFS>();
+ return std::make_unique<DFS>();
}
std::unique_ptr<WorkList> WorkList::makeBFS() {
- return llvm::make_unique<BFS>();
+ return std::make_unique<BFS>();
}
namespace {
@@ -124,7 +124,7 @@ namespace {
} // namespace
std::unique_ptr<WorkList> WorkList::makeBFSBlockDFSContents() {
- return llvm::make_unique<BFSBlockDFSContents>();
+ return std::make_unique<BFSBlockDFSContents>();
}
namespace {
@@ -186,7 +186,7 @@ public:
} // namespace
std::unique_ptr<WorkList> WorkList::makeUnexploredFirst() {
- return llvm::make_unique<UnexploredFirstStack>();
+ return std::make_unique<UnexploredFirstStack>();
}
namespace {
@@ -249,7 +249,7 @@ public:
} // namespace
std::unique_ptr<WorkList> WorkList::makeUnexploredFirstPriorityQueue() {
- return llvm::make_unique<UnexploredFirstPriorityQueue>();
+ return std::make_unique<UnexploredFirstPriorityQueue>();
}
namespace {
@@ -309,5 +309,5 @@ public:
}
std::unique_ptr<WorkList> WorkList::makeUnexploredFirstPriorityLocationQueue() {
- return llvm::make_unique<UnexploredFirstPriorityLocationQueue>();
+ return std::make_unique<UnexploredFirstPriorityLocationQueue>();
}
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 454b61fd51a1..8236907ea773 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -12,6 +12,7 @@
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
#include "ModelInjector.h"
+#include "clang/Analysis/PathDiagnostic.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -27,7 +28,6 @@
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
@@ -64,30 +64,30 @@ STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function.");
// Special PathDiagnosticConsumers.
//===----------------------------------------------------------------------===//
-void ento::createPlistHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
- PathDiagnosticConsumers &C,
- const std::string &prefix,
- const Preprocessor &PP) {
+void ento::createPlistHTMLDiagnosticConsumer(
+ AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C,
+ const std::string &prefix, const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &CTU) {
createHTMLDiagnosticConsumer(AnalyzerOpts, C,
- llvm::sys::path::parent_path(prefix), PP);
- createPlistMultiFileDiagnosticConsumer(AnalyzerOpts, C, prefix, PP);
+ llvm::sys::path::parent_path(prefix), PP, CTU);
+ createPlistMultiFileDiagnosticConsumer(AnalyzerOpts, C, prefix, PP, CTU);
}
-void ento::createTextPathDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
- PathDiagnosticConsumers &C,
- const std::string &Prefix,
- const clang::Preprocessor &PP) {
+void ento::createTextPathDiagnosticConsumer(
+ AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C,
+ const std::string &Prefix, const clang::Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &CTU) {
llvm_unreachable("'text' consumer should be enabled on ClangDiags");
}
namespace {
class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer {
DiagnosticsEngine &Diag;
- bool IncludePath, ShouldEmitAsError;
+ bool IncludePath = false, ShouldEmitAsError = false, FixitsAsRemarks = false;
public:
ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag)
- : Diag(Diag), IncludePath(false), ShouldEmitAsError(false) {}
+ : Diag(Diag) {}
~ClangDiagPathDiagConsumer() override {}
StringRef getName() const override { return "ClangDiags"; }
@@ -98,11 +98,9 @@ public:
return IncludePath ? Minimal : None;
}
- void enablePaths() {
- IncludePath = true;
- }
-
+ void enablePaths() { IncludePath = true; }
void enableWerror() { ShouldEmitAsError = true; }
+ void enableFixitsAsRemarks() { FixitsAsRemarks = true; }
void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
FilesMade *filesMade) override {
@@ -111,22 +109,46 @@ public:
? Diag.getCustomDiagID(DiagnosticsEngine::Error, "%0")
: Diag.getCustomDiagID(DiagnosticsEngine::Warning, "%0");
unsigned NoteID = Diag.getCustomDiagID(DiagnosticsEngine::Note, "%0");
-
- for (std::vector<const PathDiagnostic*>::iterator I = Diags.begin(),
- E = Diags.end(); I != E; ++I) {
+ unsigned RemarkID = Diag.getCustomDiagID(DiagnosticsEngine::Remark, "%0");
+
+ auto reportPiece =
+ [&](unsigned ID, SourceLocation Loc, StringRef String,
+ ArrayRef<SourceRange> Ranges, ArrayRef<FixItHint> Fixits) {
+ if (!FixitsAsRemarks) {
+ Diag.Report(Loc, ID) << String << Ranges << Fixits;
+ } else {
+ Diag.Report(Loc, ID) << String << Ranges;
+ for (const FixItHint &Hint : Fixits) {
+ SourceManager &SM = Diag.getSourceManager();
+ llvm::SmallString<128> Str;
+ llvm::raw_svector_ostream OS(Str);
+ // FIXME: Add support for InsertFromRange and
+ // BeforePreviousInsertion.
+ assert(!Hint.InsertFromRange.isValid() && "Not implemented yet!");
+ assert(!Hint.BeforePreviousInsertions && "Not implemented yet!");
+ OS << SM.getSpellingColumnNumber(Hint.RemoveRange.getBegin())
+ << "-" << SM.getSpellingColumnNumber(Hint.RemoveRange.getEnd())
+ << ": '" << Hint.CodeToInsert << "'";
+ Diag.Report(Loc, RemarkID) << OS.str();
+ }
+ }
+ };
+
+ for (std::vector<const PathDiagnostic *>::iterator I = Diags.begin(),
+ E = Diags.end();
+ I != E; ++I) {
const PathDiagnostic *PD = *I;
- SourceLocation WarnLoc = PD->getLocation().asLocation();
- Diag.Report(WarnLoc, WarnID) << PD->getShortDescription()
- << PD->path.back()->getRanges();
+ reportPiece(WarnID, PD->getLocation().asLocation(),
+ PD->getShortDescription(), PD->path.back()->getRanges(),
+ PD->path.back()->getFixits());
// First, add extra notes, even if paths should not be included.
for (const auto &Piece : PD->path) {
if (!isa<PathDiagnosticNotePiece>(Piece.get()))
continue;
- SourceLocation NoteLoc = Piece->getLocation().asLocation();
- Diag.Report(NoteLoc, NoteID) << Piece->getString()
- << Piece->getRanges();
+ reportPiece(NoteID, Piece->getLocation().asLocation(),
+ Piece->getString(), Piece->getRanges(), Piece->getFixits());
}
if (!IncludePath)
@@ -138,9 +160,8 @@ public:
if (isa<PathDiagnosticNotePiece>(Piece.get()))
continue;
- SourceLocation NoteLoc = Piece->getLocation().asLocation();
- Diag.Report(NoteLoc, NoteID) << Piece->getString()
- << Piece->getRanges();
+ reportPiece(NoteID, Piece->getLocation().asLocation(),
+ Piece->getString(), Piece->getRanges(), Piece->getFixits());
}
}
}
@@ -212,13 +233,13 @@ public:
Plugins(plugins), Injector(injector), CTU(CI) {
DigestAnalyzerOptions();
if (Opts->PrintStats || Opts->ShouldSerializeStats) {
- AnalyzerTimers = llvm::make_unique<llvm::TimerGroup>(
+ AnalyzerTimers = std::make_unique<llvm::TimerGroup>(
"analyzer", "Analyzer timers");
- SyntaxCheckTimer = llvm::make_unique<llvm::Timer>(
+ SyntaxCheckTimer = std::make_unique<llvm::Timer>(
"syntaxchecks", "Syntax-based analysis time", *AnalyzerTimers);
- ExprEngineTimer = llvm::make_unique<llvm::Timer>(
+ ExprEngineTimer = std::make_unique<llvm::Timer>(
"exprengine", "Path exploration time", *AnalyzerTimers);
- BugReporterTimer = llvm::make_unique<llvm::Timer>(
+ BugReporterTimer = std::make_unique<llvm::Timer>(
"bugreporter", "Path-sensitive report post-processing time",
*AnalyzerTimers);
llvm::EnableStatistics(/* PrintOnExit= */ false);
@@ -241,6 +262,9 @@ public:
if (Opts->AnalyzerWerror)
clangDiags->enableWerror();
+ if (Opts->ShouldEmitFixItHintsAsRemarks)
+ clangDiags->enableFixitsAsRemarks();
+
if (Opts->AnalysisDiagOpt == PD_TEXT) {
clangDiags->enablePaths();
@@ -249,7 +273,7 @@ public:
default:
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \
case PD_##NAME: \
- CREATEFN(*Opts.get(), PathConsumers, OutDir, PP); \
+ CREATEFN(*Opts.get(), PathConsumers, OutDir, PP, CTU); \
break;
#include "clang/StaticAnalyzer/Core/Analyses.def"
}
@@ -311,9 +335,9 @@ public:
checkerMgr = createCheckerManager(
*Ctx, *Opts, Plugins, CheckerRegistrationFns, PP.getDiagnostics());
- Mgr = llvm::make_unique<AnalysisManager>(
- *Ctx, PP.getDiagnostics(), PathConsumers, CreateStoreMgr,
- CreateConstraintMgr, checkerMgr.get(), *Opts, Injector);
+ Mgr = std::make_unique<AnalysisManager>(*Ctx, PathConsumers, CreateStoreMgr,
+ CreateConstraintMgr,
+ checkerMgr.get(), *Opts, Injector);
}
/// Store the top level decls in the set to be processed later on.
@@ -609,6 +633,7 @@ void AnalysisConsumer::runAnalysisOnTranslationUnit(ASTContext &C) {
// After all decls handled, run checkers on the entire TranslationUnit.
checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);
+ BR.FlushReports();
RecVisitorBR = nullptr;
}
@@ -626,7 +651,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
if (isBisonFile(C)) {
reportAnalyzerProgress("Skipping bison-generated file\n");
- } else if (Opts->DisableAllChecks) {
+ } else if (Opts->DisableAllCheckers) {
// Don't analyze if the user explicitly asked for no checks to be performed
// on this file.
@@ -766,6 +791,9 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
if (SyntaxCheckTimer)
SyntaxCheckTimer->stopTimer();
}
+
+ BR.FlushReports();
+
if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
RunPathSensitiveChecks(D, IMode, VisitedCallees);
if (IMode != ExprEngine::Inline_Minimal)
@@ -826,7 +854,7 @@ ento::CreateAnalysisConsumer(CompilerInstance &CI) {
AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts();
bool hasModelPath = analyzerOpts->Config.count("model-path") > 0;
- return llvm::make_unique<AnalysisConsumer>(
+ return std::make_unique<AnalysisConsumer>(
CI, CI.getFrontendOpts().OutputFile, analyzerOpts,
CI.getFrontendOpts().Plugins,
hasModelPath ? new ModelInjector(CI) : nullptr);
diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
index 1e45ee96145a..f4f06e32cd1d 100644
--- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
+++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
@@ -30,7 +30,7 @@ std::unique_ptr<CheckerManager> ento::createCheckerManager(
ArrayRef<std::string> plugins,
ArrayRef<std::function<void(CheckerRegistry &)>> checkerRegistrationFns,
DiagnosticsEngine &diags) {
- auto checkerMgr = llvm::make_unique<CheckerManager>(context, opts);
+ auto checkerMgr = std::make_unique<CheckerManager>(context, opts);
CheckerRegistry allCheckers(plugins, diags, opts, context.getLangOpts(),
checkerRegistrationFns);
@@ -74,11 +74,22 @@ void ento::printCheckerConfigList(raw_ostream &OS,
}
void ento::printAnalyzerConfigList(raw_ostream &out) {
- out << "OVERVIEW: Clang Static Analyzer -analyzer-config Option List\n\n";
- out << "USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
- out << " -analyzer-config OPTION1=VALUE, -analyzer-config "
- "OPTION2=VALUE, ...\n\n";
- out << "OPTIONS:\n\n";
+ // FIXME: This message sounds scary, should be scary, but incorrectly states
+ // that all configs are super dangerous. In reality, many of them should be
+ // accessible to the user. We should create a user-facing subset of config
+ // options under a different frontend flag.
+ out << R"(
+OVERVIEW: Clang Static Analyzer -analyzer-config Option List
+
+The following list of configurations are meant for development purposes only, as
+some of the variables they define are set to result in the most optimal
+analysis. Setting them to other values may drastically change how the analyzer
+behaves, and may even result in instabilities, crashes!
+
+USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>
+ -analyzer-config OPTION1=VALUE, -analyzer-config OPTION2=VALUE, ...
+OPTIONS:
+)";
using OptionAndDescriptionTy = std::pair<StringRef, std::string>;
OptionAndDescriptionTy PrintableOptions[] = {
diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
index 3fd4c36947cb..e00fd976f6b8 100644
--- a/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
+++ b/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
@@ -200,12 +200,12 @@ CheckerRegistry::CheckerRegistry(
// Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the
// command line.
- for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersControlList) {
+ for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersAndPackages) {
CheckerInfoListRange CheckerForCmdLineArg =
getMutableCheckersForCmdLineArg(Opt.first);
if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) {
- Diags.Report(diag::err_unknown_analyzer_checker) << Opt.first;
+ Diags.Report(diag::err_unknown_analyzer_checker_or_package) << Opt.first;
Diags.Report(diag::note_suggest_disabling_all_checkers);
}
@@ -437,7 +437,7 @@ void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const {
// Initialize the CheckerManager with all enabled checkers.
for (const auto *Checker : enabledCheckers) {
- CheckerMgr.setCurrentCheckName(CheckName(Checker->FullName));
+ CheckerMgr.setCurrentCheckerName(CheckerNameRef(Checker->FullName));
Checker->Initialize(CheckerMgr);
}
}
@@ -468,9 +468,10 @@ isOptionContainedIn(const CheckerRegistry::CmdLineOptionList &OptionList,
void CheckerRegistry::validateCheckerOptions() const {
for (const auto &Config : AnOpts.Config) {
- StringRef SuppliedChecker;
+ StringRef SuppliedCheckerOrPackage;
StringRef SuppliedOption;
- std::tie(SuppliedChecker, SuppliedOption) = Config.getKey().split(':');
+ std::tie(SuppliedCheckerOrPackage, SuppliedOption) =
+ Config.getKey().split(':');
if (SuppliedOption.empty())
continue;
@@ -483,21 +484,24 @@ void CheckerRegistry::validateCheckerOptions() const {
// Since lower_bound would look for the first element *not less* than "cor",
// it would return with an iterator to the first checker in the core, so we
// we really have to use find here, which uses operator==.
- auto CheckerIt = llvm::find(Checkers, CheckerInfo(SuppliedChecker));
+ auto CheckerIt =
+ llvm::find(Checkers, CheckerInfo(SuppliedCheckerOrPackage));
if (CheckerIt != Checkers.end()) {
- isOptionContainedIn(CheckerIt->CmdLineOptions, SuppliedChecker,
+ isOptionContainedIn(CheckerIt->CmdLineOptions, SuppliedCheckerOrPackage,
SuppliedOption, AnOpts, Diags);
continue;
}
- auto PackageIt = llvm::find(Packages, PackageInfo(SuppliedChecker));
+ auto PackageIt =
+ llvm::find(Packages, PackageInfo(SuppliedCheckerOrPackage));
if (PackageIt != Packages.end()) {
- isOptionContainedIn(PackageIt->CmdLineOptions, SuppliedChecker,
+ isOptionContainedIn(PackageIt->CmdLineOptions, SuppliedCheckerOrPackage,
SuppliedOption, AnOpts, Diags);
continue;
}
- Diags.Report(diag::err_unknown_analyzer_checker) << SuppliedChecker;
+ Diags.Report(diag::err_unknown_analyzer_checker_or_package)
+ << SuppliedCheckerOrPackage;
}
}
diff --git a/lib/StaticAnalyzer/Frontend/FrontendActions.cpp b/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
index a8af6b3d801a..04fbd0cea46b 100644
--- a/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
+++ b/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
@@ -23,5 +23,5 @@ ParseModelFileAction::ParseModelFileAction(llvm::StringMap<Stmt *> &Bodies)
std::unique_ptr<ASTConsumer>
ParseModelFileAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
- return llvm::make_unique<ModelConsumer>(Bodies);
+ return std::make_unique<ModelConsumer>(Bodies);
}
diff --git a/lib/StaticAnalyzer/Frontend/ModelInjector.cpp b/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
index fe5f59045cde..687fda75db48 100644
--- a/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
+++ b/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
@@ -9,6 +9,7 @@
#include "ModelInjector.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangStandard.h"
#include "clang/Basic/Stack.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -65,7 +66,7 @@ void ModelInjector::onBodySynthesis(const NamedDecl *D) {
auto Invocation = std::make_shared<CompilerInvocation>(CI.getInvocation());
FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
- InputKind IK = InputKind::CXX; // FIXME
+ InputKind IK = Language::CXX; // FIXME
FrontendOpts.Inputs.clear();
FrontendOpts.Inputs.emplace_back(fileName, IK);
FrontendOpts.DisableFree = true;
diff --git a/lib/Tooling/ASTDiff/ASTDiff.cpp b/lib/Tooling/ASTDiff/ASTDiff.cpp
index 69eff20bff7a..00db7702cd8b 100644
--- a/lib/Tooling/ASTDiff/ASTDiff.cpp
+++ b/lib/Tooling/ASTDiff/ASTDiff.cpp
@@ -35,8 +35,8 @@ public:
Mapping &operator=(Mapping &&Other) = default;
Mapping(size_t Size) {
- SrcToDst = llvm::make_unique<NodeId[]>(Size);
- DstToSrc = llvm::make_unique<NodeId[]>(Size);
+ SrcToDst = std::make_unique<NodeId[]>(Size);
+ DstToSrc = std::make_unique<NodeId[]>(Size);
}
void link(NodeId Src, NodeId Dst) {
@@ -565,13 +565,13 @@ public:
ZhangShashaMatcher(const ASTDiff::Impl &DiffImpl, const SyntaxTree::Impl &T1,
const SyntaxTree::Impl &T2, NodeId Id1, NodeId Id2)
: DiffImpl(DiffImpl), S1(T1, Id1), S2(T2, Id2) {
- TreeDist = llvm::make_unique<std::unique_ptr<double[]>[]>(
+ TreeDist = std::make_unique<std::unique_ptr<double[]>[]>(
size_t(S1.getSize()) + 1);
- ForestDist = llvm::make_unique<std::unique_ptr<double[]>[]>(
+ ForestDist = std::make_unique<std::unique_ptr<double[]>[]>(
size_t(S1.getSize()) + 1);
for (int I = 0, E = S1.getSize() + 1; I < E; ++I) {
- TreeDist[I] = llvm::make_unique<double[]>(size_t(S2.getSize()) + 1);
- ForestDist[I] = llvm::make_unique<double[]>(size_t(S2.getSize()) + 1);
+ TreeDist[I] = std::make_unique<double[]>(size_t(S2.getSize()) + 1);
+ ForestDist[I] = std::make_unique<double[]>(size_t(S2.getSize()) + 1);
}
}
@@ -960,7 +960,7 @@ void ASTDiff::Impl::computeChangeKinds(Mapping &M) {
ASTDiff::ASTDiff(SyntaxTree &T1, SyntaxTree &T2,
const ComparisonOptions &Options)
- : DiffImpl(llvm::make_unique<Impl>(*T1.TreeImpl, *T2.TreeImpl, Options)) {}
+ : DiffImpl(std::make_unique<Impl>(*T1.TreeImpl, *T2.TreeImpl, Options)) {}
ASTDiff::~ASTDiff() = default;
@@ -969,7 +969,7 @@ NodeId ASTDiff::getMapped(const SyntaxTree &SourceTree, NodeId Id) const {
}
SyntaxTree::SyntaxTree(ASTContext &AST)
- : TreeImpl(llvm::make_unique<SyntaxTree::Impl>(
+ : TreeImpl(std::make_unique<SyntaxTree::Impl>(
this, AST.getTranslationUnitDecl(), AST)) {}
SyntaxTree::~SyntaxTree() = default;
diff --git a/lib/Tooling/AllTUsExecution.cpp b/lib/Tooling/AllTUsExecution.cpp
index ca9db7a561be..d85075f59607 100644
--- a/lib/Tooling/AllTUsExecution.cpp
+++ b/lib/Tooling/AllTUsExecution.cpp
@@ -8,6 +8,7 @@
#include "clang/Tooling/AllTUsExecution.h"
#include "clang/Tooling/ToolExecutorPluginRegistry.h"
+#include "llvm/Support/Threading.h"
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/VirtualFileSystem.h"
@@ -147,7 +148,7 @@ llvm::Error AllTUsToolExecutor::execute(
return llvm::Error::success();
}
-static llvm::cl::opt<unsigned> ExecutorConcurrency(
+llvm::cl::opt<unsigned> ExecutorConcurrency(
"execute-concurrency",
llvm::cl::desc("The number of threads used to process all files in "
"parallel. Set to 0 for hardware concurrency. "
@@ -162,7 +163,7 @@ public:
return make_string_error(
"[AllTUsToolExecutorPlugin] Please provide a directory/file path in "
"the compilation database.");
- return llvm::make_unique<AllTUsToolExecutor>(std::move(OptionsParser),
+ return std::make_unique<AllTUsToolExecutor>(std::move(OptionsParser),
ExecutorConcurrency);
}
};
diff --git a/lib/Tooling/ArgumentsAdjusters.cpp b/lib/Tooling/ArgumentsAdjusters.cpp
index 942b35df453e..f56d08c47b9a 100644
--- a/lib/Tooling/ArgumentsAdjusters.cpp
+++ b/lib/Tooling/ArgumentsAdjusters.cpp
@@ -57,6 +57,22 @@ ArgumentsAdjuster getClangStripOutputAdjuster() {
};
}
+ArgumentsAdjuster getClangStripSerializeDiagnosticAdjuster() {
+ return [](const CommandLineArguments &Args, StringRef /*unused*/) {
+ CommandLineArguments AdjustedArgs;
+ for (size_t i = 0, e = Args.size(); i < e; ++i) {
+ StringRef Arg = Args[i];
+ if (Arg == "--serialize-diagnostics") {
+ // Skip the diagnostic output argument.
+ ++i;
+ continue;
+ }
+ AdjustedArgs.push_back(Args[i]);
+ }
+ return AdjustedArgs;
+ };
+}
+
ArgumentsAdjuster getClangStripDependencyFileAdjuster() {
return [](const CommandLineArguments &Args, StringRef /*unused*/) {
CommandLineArguments AdjustedArgs;
diff --git a/lib/Tooling/CommonOptionsParser.cpp b/lib/Tooling/CommonOptionsParser.cpp
index f7956f7998f5..5d881aab1e0d 100644
--- a/lib/Tooling/CommonOptionsParser.cpp
+++ b/lib/Tooling/CommonOptionsParser.cpp
@@ -142,7 +142,7 @@ llvm::Error CommonOptionsParser::init(
}
}
auto AdjustingCompilations =
- llvm::make_unique<ArgumentsAdjustingCompilations>(
+ std::make_unique<ArgumentsAdjustingCompilations>(
std::move(Compilations));
Adjuster =
getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN);
diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp
index 4c64750bef19..c453e8d7df19 100644
--- a/lib/Tooling/CompilationDatabase.cpp
+++ b/lib/Tooling/CompilationDatabase.cpp
@@ -356,7 +356,7 @@ FixedCompilationDatabase::loadFromCommandLine(int &Argc,
std::vector<std::string> StrippedArgs;
if (!stripPositionalArgs(CommandLine, StrippedArgs, ErrorMsg))
return nullptr;
- return llvm::make_unique<FixedCompilationDatabase>(Directory, StrippedArgs);
+ return std::make_unique<FixedCompilationDatabase>(Directory, StrippedArgs);
}
std::unique_ptr<FixedCompilationDatabase>
@@ -370,7 +370,7 @@ FixedCompilationDatabase::loadFromFile(StringRef Path, std::string &ErrorMsg) {
}
std::vector<std::string> Args{llvm::line_iterator(**File),
llvm::line_iterator()};
- return llvm::make_unique<FixedCompilationDatabase>(
+ return std::make_unique<FixedCompilationDatabase>(
llvm::sys::path::parent_path(Path), std::move(Args));
}
diff --git a/lib/Tooling/Core/Replacement.cpp b/lib/Tooling/Core/Replacement.cpp
index 546158714e3c..9ed03655bf2c 100644
--- a/lib/Tooling/Core/Replacement.cpp
+++ b/lib/Tooling/Core/Replacement.cpp
@@ -67,11 +67,11 @@ bool Replacement::isApplicable() const {
bool Replacement::apply(Rewriter &Rewrite) const {
SourceManager &SM = Rewrite.getSourceMgr();
- const FileEntry *Entry = SM.getFileManager().getFile(FilePath);
+ auto Entry = SM.getFileManager().getFile(FilePath);
if (!Entry)
return false;
- FileID ID = SM.getOrCreateFileID(Entry, SrcMgr::C_User);
+ FileID ID = SM.getOrCreateFileID(*Entry, SrcMgr::C_User);
const SourceLocation Start =
SM.getLocForStartOfFile(ID).
getLocWithOffset(ReplacementRange.getOffset());
@@ -591,7 +591,8 @@ llvm::Expected<std::string> applyAllReplacements(StringRef Code,
Rewriter Rewrite(SourceMgr, LangOptions());
InMemoryFileSystem->addFile(
"<stdin>", 0, llvm::MemoryBuffer::getMemBuffer(Code, "<stdin>"));
- FileID ID = SourceMgr.createFileID(Files.getFile("<stdin>"), SourceLocation(),
+ FileID ID = SourceMgr.createFileID(*Files.getFile("<stdin>"),
+ SourceLocation(),
clang::SrcMgr::C_User);
for (auto I = Replaces.rbegin(), E = Replaces.rend(); I != E; ++I) {
Replacement Replace("<stdin>", I->getOffset(), I->getLength(),
@@ -613,10 +614,10 @@ std::map<std::string, Replacements> groupReplacementsByFile(
std::map<std::string, Replacements> Result;
llvm::SmallPtrSet<const FileEntry *, 16> ProcessedFileEntries;
for (const auto &Entry : FileToReplaces) {
- const FileEntry *FE = FileMgr.getFile(Entry.first);
+ auto FE = FileMgr.getFile(Entry.first);
if (!FE)
llvm::errs() << "File path " << Entry.first << " is invalid.\n";
- else if (ProcessedFileEntries.insert(FE).second)
+ else if (ProcessedFileEntries.insert(*FE).second)
Result[Entry.first] = std::move(Entry.second);
}
return Result;
diff --git a/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp b/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
new file mode 100644
index 000000000000..7436c7256327
--- /dev/null
+++ b/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
@@ -0,0 +1,234 @@
+//===- DependencyScanningFilesystem.cpp - clang-scan-deps fs --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h"
+#include "clang/Lex/DependencyDirectivesSourceMinimizer.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Threading.h"
+
+using namespace clang;
+using namespace tooling;
+using namespace dependencies;
+
+CachedFileSystemEntry CachedFileSystemEntry::createFileEntry(
+ StringRef Filename, llvm::vfs::FileSystem &FS, bool Minimize) {
+ // Load the file and its content from the file system.
+ llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>> MaybeFile =
+ FS.openFileForRead(Filename);
+ if (!MaybeFile)
+ return MaybeFile.getError();
+ llvm::ErrorOr<llvm::vfs::Status> Stat = (*MaybeFile)->status();
+ if (!Stat)
+ return Stat.getError();
+
+ llvm::vfs::File &F = **MaybeFile;
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MaybeBuffer =
+ F.getBuffer(Stat->getName());
+ if (!MaybeBuffer)
+ return MaybeBuffer.getError();
+
+ llvm::SmallString<1024> MinimizedFileContents;
+ // Minimize the file down to directives that might affect the dependencies.
+ const auto &Buffer = *MaybeBuffer;
+ SmallVector<minimize_source_to_dependency_directives::Token, 64> Tokens;
+ if (!Minimize || minimizeSourceToDependencyDirectives(
+ Buffer->getBuffer(), MinimizedFileContents, Tokens)) {
+ // Use the original file unless requested otherwise, or
+ // if the minimization failed.
+ // FIXME: Propage the diagnostic if desired by the client.
+ CachedFileSystemEntry Result;
+ Result.MaybeStat = std::move(*Stat);
+ Result.Contents.reserve(Buffer->getBufferSize() + 1);
+ Result.Contents.append(Buffer->getBufferStart(), Buffer->getBufferEnd());
+ // Implicitly null terminate the contents for Clang's lexer.
+ Result.Contents.push_back('\0');
+ Result.Contents.pop_back();
+ return Result;
+ }
+
+ CachedFileSystemEntry Result;
+ size_t Size = MinimizedFileContents.size();
+ Result.MaybeStat = llvm::vfs::Status(Stat->getName(), Stat->getUniqueID(),
+ Stat->getLastModificationTime(),
+ Stat->getUser(), Stat->getGroup(), Size,
+ Stat->getType(), Stat->getPermissions());
+ // The contents produced by the minimizer must be null terminated.
+ assert(MinimizedFileContents.data()[MinimizedFileContents.size()] == '\0' &&
+ "not null terminated contents");
+ // Even though there's an implicit null terminator in the minimized contents,
+ // we want to temporarily make it explicit. This will ensure that the
+ // std::move will preserve it even if it needs to do a copy if the
+ // SmallString still has the small capacity.
+ MinimizedFileContents.push_back('\0');
+ Result.Contents = std::move(MinimizedFileContents);
+ // Now make the null terminator implicit again, so that Clang's lexer can find
+ // it right where the buffer ends.
+ Result.Contents.pop_back();
+
+ // Compute the skipped PP ranges that speedup skipping over inactive
+ // preprocessor blocks.
+ llvm::SmallVector<minimize_source_to_dependency_directives::SkippedRange, 32>
+ SkippedRanges;
+ minimize_source_to_dependency_directives::computeSkippedRanges(Tokens,
+ SkippedRanges);
+ PreprocessorSkippedRangeMapping Mapping;
+ for (const auto &Range : SkippedRanges) {
+ if (Range.Length < 16) {
+ // Ignore small ranges as non-profitable.
+ // FIXME: This is a heuristic, its worth investigating the tradeoffs
+ // when it should be applied.
+ continue;
+ }
+ Mapping[Range.Offset] = Range.Length;
+ }
+ Result.PPSkippedRangeMapping = std::move(Mapping);
+
+ return Result;
+}
+
+CachedFileSystemEntry
+CachedFileSystemEntry::createDirectoryEntry(llvm::vfs::Status &&Stat) {
+ assert(Stat.isDirectory() && "not a directory!");
+ auto Result = CachedFileSystemEntry();
+ Result.MaybeStat = std::move(Stat);
+ return Result;
+}
+
+DependencyScanningFilesystemSharedCache::
+ DependencyScanningFilesystemSharedCache() {
+ // This heuristic was chosen using a empirical testing on a
+ // reasonably high core machine (iMacPro 18 cores / 36 threads). The cache
+ // sharding gives a performance edge by reducing the lock contention.
+ // FIXME: A better heuristic might also consider the OS to account for
+ // the different cost of lock contention on different OSes.
+ NumShards = std::max(2u, llvm::hardware_concurrency() / 4);
+ CacheShards = std::make_unique<CacheShard[]>(NumShards);
+}
+
+/// Returns a cache entry for the corresponding key.
+///
+/// A new cache entry is created if the key is not in the cache. This is a
+/// thread safe call.
+DependencyScanningFilesystemSharedCache::SharedFileSystemEntry &
+DependencyScanningFilesystemSharedCache::get(StringRef Key) {
+ CacheShard &Shard = CacheShards[llvm::hash_value(Key) % NumShards];
+ std::unique_lock<std::mutex> LockGuard(Shard.CacheLock);
+ auto It = Shard.Cache.try_emplace(Key);
+ return It.first->getValue();
+}
+
+llvm::ErrorOr<const CachedFileSystemEntry *>
+DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry(
+ const StringRef Filename) {
+ if (const CachedFileSystemEntry *Entry = getCachedEntry(Filename)) {
+ return Entry;
+ }
+
+ // FIXME: Handle PCM/PCH files.
+ // FIXME: Handle module map files.
+
+ bool KeepOriginalSource = IgnoredFiles.count(Filename);
+ DependencyScanningFilesystemSharedCache::SharedFileSystemEntry
+ &SharedCacheEntry = SharedCache.get(Filename);
+ const CachedFileSystemEntry *Result;
+ {
+ std::unique_lock<std::mutex> LockGuard(SharedCacheEntry.ValueLock);
+ CachedFileSystemEntry &CacheEntry = SharedCacheEntry.Value;
+
+ if (!CacheEntry.isValid()) {
+ llvm::vfs::FileSystem &FS = getUnderlyingFS();
+ auto MaybeStatus = FS.status(Filename);
+ if (!MaybeStatus)
+ CacheEntry = CachedFileSystemEntry(MaybeStatus.getError());
+ else if (MaybeStatus->isDirectory())
+ CacheEntry = CachedFileSystemEntry::createDirectoryEntry(
+ std::move(*MaybeStatus));
+ else
+ CacheEntry = CachedFileSystemEntry::createFileEntry(
+ Filename, FS, !KeepOriginalSource);
+ }
+
+ Result = &CacheEntry;
+ }
+
+ // Store the result in the local cache.
+ setCachedEntry(Filename, Result);
+ return Result;
+}
+
+llvm::ErrorOr<llvm::vfs::Status>
+DependencyScanningWorkerFilesystem::status(const Twine &Path) {
+ SmallString<256> OwnedFilename;
+ StringRef Filename = Path.toStringRef(OwnedFilename);
+ const llvm::ErrorOr<const CachedFileSystemEntry *> Result =
+ getOrCreateFileSystemEntry(Filename);
+ if (!Result)
+ return Result.getError();
+ return (*Result)->getStatus();
+}
+
+namespace {
+
+/// The VFS that is used by clang consumes the \c CachedFileSystemEntry using
+/// this subclass.
+class MinimizedVFSFile final : public llvm::vfs::File {
+public:
+ MinimizedVFSFile(std::unique_ptr<llvm::MemoryBuffer> Buffer,
+ llvm::vfs::Status Stat)
+ : Buffer(std::move(Buffer)), Stat(std::move(Stat)) {}
+
+ llvm::ErrorOr<llvm::vfs::Status> status() override { return Stat; }
+
+ const llvm::MemoryBuffer *getBufferPtr() const { return Buffer.get(); }
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
+ bool IsVolatile) override {
+ return std::move(Buffer);
+ }
+
+ std::error_code close() override { return {}; }
+
+private:
+ std::unique_ptr<llvm::MemoryBuffer> Buffer;
+ llvm::vfs::Status Stat;
+};
+
+llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
+createFile(const CachedFileSystemEntry *Entry,
+ ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings) {
+ if (Entry->isDirectory())
+ return llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>(
+ std::make_error_code(std::errc::is_a_directory));
+ llvm::ErrorOr<StringRef> Contents = Entry->getContents();
+ if (!Contents)
+ return Contents.getError();
+ auto Result = std::make_unique<MinimizedVFSFile>(
+ llvm::MemoryBuffer::getMemBuffer(*Contents, Entry->getName(),
+ /*RequiresNullTerminator=*/false),
+ *Entry->getStatus());
+ if (!Entry->getPPSkippedRangeMapping().empty() && PPSkipMappings)
+ (*PPSkipMappings)[Result->getBufferPtr()] =
+ &Entry->getPPSkippedRangeMapping();
+ return llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>(
+ std::unique_ptr<llvm::vfs::File>(std::move(Result)));
+}
+
+} // end anonymous namespace
+
+llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
+DependencyScanningWorkerFilesystem::openFileForRead(const Twine &Path) {
+ SmallString<256> OwnedFilename;
+ StringRef Filename = Path.toStringRef(OwnedFilename);
+
+ const llvm::ErrorOr<const CachedFileSystemEntry *> Result =
+ getOrCreateFileSystemEntry(Filename);
+ if (!Result)
+ return Result.getError();
+ return createFile(Result.get(), PPSkipMappings);
+}
diff --git a/lib/Tooling/DependencyScanning/DependencyScanningService.cpp b/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
new file mode 100644
index 000000000000..e5cebe381000
--- /dev/null
+++ b/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
@@ -0,0 +1,19 @@
+//===- DependencyScanningService.cpp - clang-scan-deps service ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
+
+using namespace clang;
+using namespace tooling;
+using namespace dependencies;
+
+DependencyScanningService::DependencyScanningService(ScanningMode Mode,
+ bool ReuseFileManager,
+ bool SkipExcludedPPRanges)
+ : Mode(Mode), ReuseFileManager(ReuseFileManager),
+ SkipExcludedPPRanges(SkipExcludedPPRanges) {}
diff --git a/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
new file mode 100644
index 000000000000..82b3ae806c65
--- /dev/null
+++ b/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -0,0 +1,71 @@
+//===- DependencyScanningTool.cpp - clang-scan-deps service ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
+#include "clang/Frontend/Utils.h"
+
+namespace clang{
+namespace tooling{
+namespace dependencies{
+
+DependencyScanningTool::DependencyScanningTool(DependencyScanningService &Service,
+const tooling::CompilationDatabase &Compilations) : Worker(Service), Compilations(Compilations) {}
+
+llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(const std::string &Input,
+ StringRef CWD) {
+ /// Prints out all of the gathered dependencies into a string.
+ class DependencyPrinterConsumer : public DependencyConsumer {
+ public:
+ void handleFileDependency(const DependencyOutputOptions &Opts,
+ StringRef File) override {
+ if (!this->Opts)
+ this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
+ Dependencies.push_back(File);
+ }
+
+ void printDependencies(std::string &S) {
+ if (!Opts)
+ return;
+
+ class DependencyPrinter : public DependencyFileGenerator {
+ public:
+ DependencyPrinter(DependencyOutputOptions &Opts,
+ ArrayRef<std::string> Dependencies)
+ : DependencyFileGenerator(Opts) {
+ for (const auto &Dep : Dependencies)
+ addDependency(Dep);
+ }
+
+ void printDependencies(std::string &S) {
+ llvm::raw_string_ostream OS(S);
+ outputDependencyFile(OS);
+ }
+ };
+
+ DependencyPrinter Generator(*Opts, Dependencies);
+ Generator.printDependencies(S);
+ }
+
+ private:
+ std::unique_ptr<DependencyOutputOptions> Opts;
+ std::vector<std::string> Dependencies;
+ };
+
+ DependencyPrinterConsumer Consumer;
+ auto Result =
+ Worker.computeDependencies(Input, CWD, Compilations, Consumer);
+ if (Result)
+ return std::move(Result);
+ std::string Output;
+ Consumer.printDependencies(Output);
+ return Output;
+}
+
+} // end namespace dependencies
+} // end namespace tooling
+} // end namespace clang
diff --git a/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index 4868f2663796..f382c202f8c2 100644
--- a/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -8,9 +8,12 @@
#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
#include "clang/Tooling/Tooling.h"
using namespace clang;
@@ -19,21 +22,25 @@ using namespace dependencies;
namespace {
-/// Prints out all of the gathered dependencies into a string.
-class DependencyPrinter : public DependencyFileGenerator {
+/// Forwards the gatherered dependencies to the consumer.
+class DependencyConsumerForwarder : public DependencyFileGenerator {
public:
- DependencyPrinter(std::unique_ptr<DependencyOutputOptions> Opts,
- std::string &S)
- : DependencyFileGenerator(*Opts), Opts(std::move(Opts)), S(S) {}
+ DependencyConsumerForwarder(std::unique_ptr<DependencyOutputOptions> Opts,
+ DependencyConsumer &C)
+ : DependencyFileGenerator(*Opts), Opts(std::move(Opts)), C(C) {}
void finishedMainFile(DiagnosticsEngine &Diags) override {
- llvm::raw_string_ostream OS(S);
- outputDependencyFile(OS);
+ llvm::SmallString<256> CanonPath;
+ for (const auto &File : getDependencies()) {
+ CanonPath = File;
+ llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true);
+ C.handleFileDependency(*Opts, CanonPath);
+ }
}
private:
std::unique_ptr<DependencyOutputOptions> Opts;
- std::string &S;
+ DependencyConsumer &C;
};
/// A proxy file system that doesn't call `chdir` when changing the working
@@ -62,10 +69,12 @@ private:
/// dependency scanning for the given compiler invocation.
class DependencyScanningAction : public tooling::ToolAction {
public:
- DependencyScanningAction(StringRef WorkingDirectory,
- std::string &DependencyFileContents)
- : WorkingDirectory(WorkingDirectory),
- DependencyFileContents(DependencyFileContents) {}
+ DependencyScanningAction(
+ StringRef WorkingDirectory, DependencyConsumer &Consumer,
+ llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS,
+ ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings)
+ : WorkingDirectory(WorkingDirectory), Consumer(Consumer),
+ DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings) {}
bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
FileManager *FileMgr,
@@ -74,8 +83,6 @@ public:
// Create a compiler instance to handle the actual work.
CompilerInstance Compiler(std::move(PCHContainerOps));
Compiler.setInvocation(std::move(Invocation));
- FileMgr->getFileSystemOpts().WorkingDir = WorkingDirectory;
- Compiler.setFileManager(FileMgr);
// Don't print 'X warnings and Y errors generated'.
Compiler.getDiagnosticOpts().ShowCarets = false;
@@ -84,6 +91,32 @@ public:
if (!Compiler.hasDiagnostics())
return false;
+ // Use the dependency scanning optimized file system if we can.
+ if (DepFS) {
+ const CompilerInvocation &CI = Compiler.getInvocation();
+ // Add any filenames that were explicity passed in the build settings and
+ // that might be opened, as we want to ensure we don't run source
+ // minimization on them.
+ DepFS->IgnoredFiles.clear();
+ for (const auto &Entry : CI.getHeaderSearchOpts().UserEntries)
+ DepFS->IgnoredFiles.insert(Entry.Path);
+ for (const auto &Entry : CI.getHeaderSearchOpts().VFSOverlayFiles)
+ DepFS->IgnoredFiles.insert(Entry);
+
+ // Support for virtual file system overlays on top of the caching
+ // filesystem.
+ FileMgr->setVirtualFileSystem(createVFSFromCompilerInvocation(
+ CI, Compiler.getDiagnostics(), DepFS));
+
+ // Pass the skip mappings which should speed up excluded conditional block
+ // skipping in the preprocessor.
+ if (PPSkipMappings)
+ Compiler.getPreprocessorOpts()
+ .ExcludedConditionalDirectiveSkipMappings = PPSkipMappings;
+ }
+
+ FileMgr->getFileSystemOpts().WorkingDir = WorkingDirectory;
+ Compiler.setFileManager(FileMgr);
Compiler.createSourceManager(*FileMgr);
// Create the dependency collector that will collect the produced
@@ -93,57 +126,76 @@ public:
// invocation to the collector. The options in the invocation are reset,
// which ensures that the compiler won't create new dependency collectors,
// and thus won't write out the extra '.d' files to disk.
- auto Opts = llvm::make_unique<DependencyOutputOptions>(
+ auto Opts = std::make_unique<DependencyOutputOptions>(
std::move(Compiler.getInvocation().getDependencyOutputOpts()));
// We need at least one -MT equivalent for the generator to work.
if (Opts->Targets.empty())
Opts->Targets = {"clang-scan-deps dependency"};
- Compiler.addDependencyCollector(std::make_shared<DependencyPrinter>(
- std::move(Opts), DependencyFileContents));
+ Compiler.addDependencyCollector(
+ std::make_shared<DependencyConsumerForwarder>(std::move(Opts),
+ Consumer));
- auto Action = llvm::make_unique<PreprocessOnlyAction>();
+ auto Action = std::make_unique<PreprocessOnlyAction>();
const bool Result = Compiler.ExecuteAction(*Action);
- FileMgr->clearStatCache();
+ if (!DepFS)
+ FileMgr->clearStatCache();
return Result;
}
private:
StringRef WorkingDirectory;
- /// The dependency file will be written to this string.
- std::string &DependencyFileContents;
+ DependencyConsumer &Consumer;
+ llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;
+ ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings;
};
} // end anonymous namespace
-DependencyScanningWorker::DependencyScanningWorker() {
+DependencyScanningWorker::DependencyScanningWorker(
+ DependencyScanningService &Service) {
DiagOpts = new DiagnosticOptions();
PCHContainerOps = std::make_shared<PCHContainerOperations>();
- /// FIXME: Use the shared file system from the service for fast scanning
- /// mode.
- WorkerFS = new ProxyFileSystemWithoutChdir(llvm::vfs::getRealFileSystem());
+ RealFS = new ProxyFileSystemWithoutChdir(llvm::vfs::getRealFileSystem());
+ if (Service.canSkipExcludedPPRanges())
+ PPSkipMappings =
+ std::make_unique<ExcludedPreprocessorDirectiveSkipMapping>();
+ if (Service.getMode() == ScanningMode::MinimizedSourcePreprocessing)
+ DepFS = new DependencyScanningWorkerFilesystem(
+ Service.getSharedCache(), RealFS, PPSkipMappings.get());
+ if (Service.canReuseFileManager())
+ Files = new FileManager(FileSystemOptions(), RealFS);
}
-llvm::Expected<std::string>
-DependencyScanningWorker::getDependencyFile(const std::string &Input,
- StringRef WorkingDirectory,
- const CompilationDatabase &CDB) {
+static llvm::Error runWithDiags(
+ DiagnosticOptions *DiagOpts,
+ llvm::function_ref<bool(DiagnosticConsumer &DC)> BodyShouldSucceed) {
// Capture the emitted diagnostics and report them to the client
// in the case of a failure.
std::string DiagnosticOutput;
llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput);
- TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.get());
-
- WorkerFS->setCurrentWorkingDirectory(WorkingDirectory);
- tooling::ClangTool Tool(CDB, Input, PCHContainerOps, WorkerFS);
- Tool.clearArgumentsAdjusters();
- Tool.setRestoreWorkingDir(false);
- Tool.setPrintErrorMessage(false);
- Tool.setDiagnosticConsumer(&DiagPrinter);
- std::string Output;
- DependencyScanningAction Action(WorkingDirectory, Output);
- if (Tool.run(&Action)) {
- return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
- llvm::inconvertibleErrorCode());
- }
- return Output;
+ TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts);
+
+ if (BodyShouldSucceed(DiagPrinter))
+ return llvm::Error::success();
+ return llvm::make_error<llvm::StringError>(DiagnosticsOS.str(),
+ llvm::inconvertibleErrorCode());
+}
+
+llvm::Error DependencyScanningWorker::computeDependencies(
+ const std::string &Input, StringRef WorkingDirectory,
+ const CompilationDatabase &CDB, DependencyConsumer &Consumer) {
+ RealFS->setCurrentWorkingDirectory(WorkingDirectory);
+ return runWithDiags(DiagOpts.get(), [&](DiagnosticConsumer &DC) {
+ /// Create the tool that uses the underlying file system to ensure that any
+ /// file system requests that are made by the driver do not go through the
+ /// dependency scanning filesystem.
+ tooling::ClangTool Tool(CDB, Input, PCHContainerOps, RealFS, Files);
+ Tool.clearArgumentsAdjusters();
+ Tool.setRestoreWorkingDir(false);
+ Tool.setPrintErrorMessage(false);
+ Tool.setDiagnosticConsumer(&DC);
+ DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS,
+ PPSkipMappings.get());
+ return !Tool.run(&Action);
+ });
}
diff --git a/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp b/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp
index ac3faf1b01f9..b6c1c0952aca 100644
--- a/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp
+++ b/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp
@@ -50,7 +50,7 @@ private:
std::unique_ptr<CompilationDatabase>
inferTargetAndDriverMode(std::unique_ptr<CompilationDatabase> Base) {
- return llvm::make_unique<TargetAndModeAdderDatabase>(std::move(Base));
+ return std::make_unique<TargetAndModeAdderDatabase>(std::move(Base));
}
} // namespace tooling
diff --git a/lib/Tooling/Inclusions/HeaderIncludes.cpp b/lib/Tooling/Inclusions/HeaderIncludes.cpp
index a7f79c33bc55..e746bbb7f87b 100644
--- a/lib/Tooling/Inclusions/HeaderIncludes.cpp
+++ b/lib/Tooling/Inclusions/HeaderIncludes.cpp
@@ -199,6 +199,20 @@ int IncludeCategoryManager::getIncludePriority(StringRef IncludeName,
return Ret;
}
+int IncludeCategoryManager::getSortIncludePriority(StringRef IncludeName,
+ bool CheckMainHeader) const {
+ int Ret = INT_MAX;
+ for (unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i)
+ if (CategoryRegexs[i].match(IncludeName)) {
+ Ret = Style.IncludeCategories[i].SortPriority;
+ if (Ret == 0)
+ Ret = Style.IncludeCategories[i].Priority;
+ break;
+ }
+ if (CheckMainHeader && IsMainFile && Ret > 0 && isMainHeader(IncludeName))
+ Ret = 0;
+ return Ret;
+}
bool IncludeCategoryManager::isMainHeader(StringRef IncludeName) const {
if (!IncludeName.startswith("\""))
return false;
diff --git a/lib/Tooling/Inclusions/IncludeStyle.cpp b/lib/Tooling/Inclusions/IncludeStyle.cpp
index c53c82c83630..26dc0b87cf9d 100644
--- a/lib/Tooling/Inclusions/IncludeStyle.cpp
+++ b/lib/Tooling/Inclusions/IncludeStyle.cpp
@@ -17,6 +17,7 @@ void MappingTraits<IncludeStyle::IncludeCategory>::mapping(
IO &IO, IncludeStyle::IncludeCategory &Category) {
IO.mapOptional("Regex", Category.Regex);
IO.mapOptional("Priority", Category.Priority);
+ IO.mapOptional("SortPriority", Category.SortPriority);
}
void ScalarEnumerationTraits<IncludeStyle::IncludeBlocksStyle>::enumeration(
diff --git a/lib/Tooling/InterpolatingCompilationDatabase.cpp b/lib/Tooling/InterpolatingCompilationDatabase.cpp
index 53c8dd448fd9..59b66abe65e9 100644
--- a/lib/Tooling/InterpolatingCompilationDatabase.cpp
+++ b/lib/Tooling/InterpolatingCompilationDatabase.cpp
@@ -42,9 +42,9 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/LangStandard.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Types.h"
-#include "clang/Frontend/LangStandard.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
@@ -149,17 +149,17 @@ struct TransferableCommand {
// We parse each argument individually so that we can retain the exact
// spelling of each argument; re-rendering is lossy for aliased flags.
// E.g. in CL mode, /W4 maps to -Wall.
- auto OptTable = clang::driver::createDriverOptTable();
+ auto &OptTable = clang::driver::getDriverOptTable();
if (!OldArgs.empty())
Cmd.CommandLine.emplace_back(OldArgs.front());
for (unsigned Pos = 1; Pos < OldArgs.size();) {
using namespace driver::options;
const unsigned OldPos = Pos;
- std::unique_ptr<llvm::opt::Arg> Arg(OptTable->ParseOneArg(
+ std::unique_ptr<llvm::opt::Arg> Arg(OptTable.ParseOneArg(
ArgList, Pos,
- /* Include */ClangCLMode ? CoreOption | CLOption : 0,
- /* Exclude */ClangCLMode ? 0 : CLOption));
+ /* Include */ ClangCLMode ? CoreOption | CLOption : 0,
+ /* Exclude */ ClangCLMode ? 0 : CLOption));
if (!Arg)
continue;
@@ -249,15 +249,15 @@ private:
}
// Map the language from the --std flag to that of the -x flag.
- static types::ID toType(InputKind::Language Lang) {
+ static types::ID toType(Language Lang) {
switch (Lang) {
- case InputKind::C:
+ case Language::C:
return types::TY_C;
- case InputKind::CXX:
+ case Language::CXX:
return types::TY_CXX;
- case InputKind::ObjC:
+ case Language::ObjC:
return types::TY_ObjC;
- case InputKind::ObjCXX:
+ case Language::ObjCXX:
return types::TY_ObjCXX;
default:
return types::TY_INVALID;
@@ -297,15 +297,8 @@ private:
// Try to interpret the argument as '-std='.
Optional<LangStandard::Kind> tryParseStdArg(const llvm::opt::Arg &Arg) {
using namespace driver::options;
- if (Arg.getOption().matches(ClangCLMode ? OPT__SLASH_std : OPT_std_EQ)) {
- return llvm::StringSwitch<LangStandard::Kind>(Arg.getValue())
-#define LANGSTANDARD(id, name, lang, ...) .Case(name, LangStandard::lang_##id)
-#define LANGSTANDARD_ALIAS(id, alias) .Case(alias, LangStandard::lang_##id)
-#include "clang/Frontend/LangStandards.def"
-#undef LANGSTANDARD_ALIAS
-#undef LANGSTANDARD
- .Default(LangStandard::lang_unspecified);
- }
+ if (Arg.getOption().matches(ClangCLMode ? OPT__SLASH_std : OPT_std_EQ))
+ return LangStandard::getLangKind(Arg.getValue());
return None;
}
};
@@ -544,7 +537,7 @@ private:
std::unique_ptr<CompilationDatabase>
inferMissingCompileCommands(std::unique_ptr<CompilationDatabase> Inner) {
- return llvm::make_unique<InterpolatingCompilationDatabase>(std::move(Inner));
+ return std::make_unique<InterpolatingCompilationDatabase>(std::move(Inner));
}
} // namespace tooling
diff --git a/lib/Tooling/Refactoring.cpp b/lib/Tooling/Refactoring.cpp
index f379a9c3bcf6..d45cd8c57f10 100644
--- a/lib/Tooling/Refactoring.cpp
+++ b/lib/Tooling/Refactoring.cpp
@@ -78,7 +78,10 @@ bool formatAndApplyAllReplacements(
const std::string &FilePath = FileAndReplaces.first;
auto &CurReplaces = FileAndReplaces.second;
- const FileEntry *Entry = Files.getFile(FilePath);
+ const FileEntry *Entry = nullptr;
+ if (auto File = Files.getFile(FilePath))
+ Entry = *File;
+
FileID ID = SM.getOrCreateFileID(Entry, SrcMgr::C_User);
StringRef Code = SM.getBufferData(ID);
diff --git a/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp b/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
index 14fc66a979ae..7dfd3988d904 100644
--- a/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
+++ b/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp
@@ -35,7 +35,7 @@ Expected<CodeRangeASTSelection> CodeRangeASTSelectionRequirement::evaluate(
if (!ASTSelection)
return ASTSelection.takeError();
std::unique_ptr<SelectedASTNode> StoredSelection =
- llvm::make_unique<SelectedASTNode>(std::move(*ASTSelection));
+ std::make_unique<SelectedASTNode>(std::move(*ASTSelection));
Optional<CodeRangeASTSelection> CodeRange = CodeRangeASTSelection::create(
Context.getSelectionRange(), *StoredSelection);
if (!CodeRange)
diff --git a/lib/Tooling/Refactoring/Extract/Extract.cpp b/lib/Tooling/Refactoring/Extract/Extract.cpp
index f5b94a462103..402b56109052 100644
--- a/lib/Tooling/Refactoring/Extract/Extract.cpp
+++ b/lib/Tooling/Refactoring/Extract/Extract.cpp
@@ -13,12 +13,12 @@
//===----------------------------------------------------------------------===//
#include "clang/Tooling/Refactoring/Extract/Extract.h"
-#include "SourceExtraction.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/Refactoring/Extract/SourceExtraction.h"
namespace clang {
namespace tooling {
diff --git a/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp b/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp
index 533c373e35c4..5d57ecf90a96 100644
--- a/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp
+++ b/lib/Tooling/Refactoring/Extract/SourceExtraction.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "SourceExtraction.h"
+#include "clang/Tooling/Refactoring/Extract/SourceExtraction.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
@@ -40,8 +40,12 @@ bool isSemicolonRequiredAfter(const Stmt *S) {
return isSemicolonRequiredAfter(CXXFor->getBody());
if (const auto *ObjCFor = dyn_cast<ObjCForCollectionStmt>(S))
return isSemicolonRequiredAfter(ObjCFor->getBody());
+ if(const auto *Switch = dyn_cast<SwitchStmt>(S))
+ return isSemicolonRequiredAfter(Switch->getBody());
+ if(const auto *Case = dyn_cast<SwitchCase>(S))
+ return isSemicolonRequiredAfter(Case->getSubStmt());
switch (S->getStmtClass()) {
- case Stmt::SwitchStmtClass:
+ case Stmt::DeclStmtClass:
case Stmt::CXXTryStmtClass:
case Stmt::ObjCAtSynchronizedStmtClass:
case Stmt::ObjCAutoreleasePoolStmtClass:
diff --git a/lib/Tooling/Refactoring/RefactoringActions.cpp b/lib/Tooling/Refactoring/RefactoringActions.cpp
index 1a3833243ab4..7ac723f67c04 100644
--- a/lib/Tooling/Refactoring/RefactoringActions.cpp
+++ b/lib/Tooling/Refactoring/RefactoringActions.cpp
@@ -98,8 +98,8 @@ public:
std::vector<std::unique_ptr<RefactoringAction>> createRefactoringActions() {
std::vector<std::unique_ptr<RefactoringAction>> Actions;
- Actions.push_back(llvm::make_unique<LocalRename>());
- Actions.push_back(llvm::make_unique<ExtractRefactoring>());
+ Actions.push_back(std::make_unique<LocalRename>());
+ Actions.push_back(std::make_unique<ExtractRefactoring>());
return Actions;
}
diff --git a/lib/Tooling/Refactoring/Rename/RenamingAction.cpp b/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
index 1649513a077a..b0634912e3fc 100644
--- a/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
+++ b/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
@@ -266,12 +266,12 @@ private:
};
std::unique_ptr<ASTConsumer> RenamingAction::newASTConsumer() {
- return llvm::make_unique<RenamingASTConsumer>(NewNames, PrevNames, USRList,
+ return std::make_unique<RenamingASTConsumer>(NewNames, PrevNames, USRList,
FileToReplaces, PrintLocations);
}
std::unique_ptr<ASTConsumer> QualifiedRenamingAction::newASTConsumer() {
- return llvm::make_unique<USRSymbolRenamer>(NewNames, USRList, FileToReplaces);
+ return std::make_unique<USRSymbolRenamer>(NewNames, USRList, FileToReplaces);
}
} // end namespace tooling
diff --git a/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp b/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp
index 8cc1ffaf4482..9e69d37e81ad 100644
--- a/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp
+++ b/lib/Tooling/Refactoring/Rename/SymbolOccurrences.cpp
@@ -25,7 +25,7 @@ SymbolOccurrence::SymbolOccurrence(const SymbolName &Name, OccurrenceKind Kind,
Locations[0], Locations[0].getLocWithOffset(NamePieces[0].size()));
return;
}
- MultipleRanges = llvm::make_unique<SourceRange[]>(Locations.size());
+ MultipleRanges = std::make_unique<SourceRange[]>(Locations.size());
RangeOrNumRanges.setBegin(
SourceLocation::getFromRawEncoding(Locations.size()));
for (const auto &Loc : llvm::enumerate(Locations)) {
diff --git a/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp b/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
index 54c6f3e734b1..e26248f50c29 100644
--- a/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
+++ b/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp
@@ -102,6 +102,10 @@ public:
private:
void handleCXXRecordDecl(const CXXRecordDecl *RecordDecl) {
+ if (!RecordDecl->getDefinition()) {
+ USRSet.insert(getUSRForDecl(RecordDecl));
+ return;
+ }
RecordDecl = RecordDecl->getDefinition();
if (const auto *ClassTemplateSpecDecl =
dyn_cast<ClassTemplateSpecializationDecl>(RecordDecl))
@@ -264,7 +268,7 @@ private:
};
std::unique_ptr<ASTConsumer> USRFindingAction::newASTConsumer() {
- return llvm::make_unique<NamedDeclFindingConsumer>(
+ return std::make_unique<NamedDeclFindingConsumer>(
SymbolOffsets, QualifiedNames, SpellingNames, USRList, Force,
ErrorOccurred);
}
diff --git a/lib/Tooling/Refactoring/SourceCode.cpp b/lib/Tooling/Refactoring/SourceCode.cpp
deleted file mode 100644
index 3a97e178bbd4..000000000000
--- a/lib/Tooling/Refactoring/SourceCode.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-//===--- SourceCode.cpp - Source code manipulation routines -----*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file provides functions that simplify extraction of source code.
-//
-//===----------------------------------------------------------------------===//
-#include "clang/Tooling/Refactoring/SourceCode.h"
-#include "clang/Lex/Lexer.h"
-
-using namespace clang;
-
-StringRef clang::tooling::getText(CharSourceRange Range,
- const ASTContext &Context) {
- return Lexer::getSourceText(Range, Context.getSourceManager(),
- Context.getLangOpts());
-}
-
-CharSourceRange clang::tooling::maybeExtendRange(CharSourceRange Range,
- tok::TokenKind Next,
- ASTContext &Context) {
- Optional<Token> Tok = Lexer::findNextToken(
- Range.getEnd(), Context.getSourceManager(), Context.getLangOpts());
- if (!Tok || !Tok->is(Next))
- return Range;
- return CharSourceRange::getTokenRange(Range.getBegin(), Tok->getLocation());
-}
diff --git a/lib/Tooling/Refactoring/Stencil.cpp b/lib/Tooling/Refactoring/Stencil.cpp
deleted file mode 100644
index 09eca21c3cef..000000000000
--- a/lib/Tooling/Refactoring/Stencil.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-//===--- Stencil.cpp - Stencil implementation -------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Tooling/Refactoring/Stencil.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTTypeTraits.h"
-#include "clang/AST/Expr.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/ASTMatchers/ASTMatchers.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Tooling/Refactoring/SourceCode.h"
-#include "llvm/Support/Errc.h"
-#include <atomic>
-#include <memory>
-#include <string>
-
-using namespace clang;
-using namespace tooling;
-
-using ast_matchers::MatchFinder;
-using llvm::Error;
-
-// A down_cast function to safely down cast a StencilPartInterface to a subclass
-// D. Returns nullptr if P is not an instance of D.
-template <typename D> const D *down_cast(const StencilPartInterface *P) {
- if (P == nullptr || D::typeId() != P->typeId())
- return nullptr;
- return static_cast<const D *>(P);
-}
-
-static llvm::Expected<ast_type_traits::DynTypedNode>
-getNode(const ast_matchers::BoundNodes &Nodes, StringRef Id) {
- auto &NodesMap = Nodes.getMap();
- auto It = NodesMap.find(Id);
- if (It == NodesMap.end())
- return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
- "Id not bound: " + Id);
- return It->second;
-}
-
-namespace {
-// An arbitrary fragment of code within a stencil.
-struct RawTextData {
- explicit RawTextData(std::string T) : Text(std::move(T)) {}
- std::string Text;
-};
-
-// A debugging operation to dump the AST for a particular (bound) AST node.
-struct DebugPrintNodeOpData {
- explicit DebugPrintNodeOpData(std::string S) : Id(std::move(S)) {}
- std::string Id;
-};
-
-// The fragment of code corresponding to the selected range.
-struct SelectorOpData {
- explicit SelectorOpData(RangeSelector S) : Selector(std::move(S)) {}
- RangeSelector Selector;
-};
-} // namespace
-
-bool isEqualData(const RawTextData &A, const RawTextData &B) {
- return A.Text == B.Text;
-}
-
-bool isEqualData(const DebugPrintNodeOpData &A, const DebugPrintNodeOpData &B) {
- return A.Id == B.Id;
-}
-
-// Equality is not (yet) defined for \c RangeSelector.
-bool isEqualData(const SelectorOpData &, const SelectorOpData &) { return false; }
-
-// The `evalData()` overloads evaluate the given stencil data to a string, given
-// the match result, and append it to `Result`. We define an overload for each
-// type of stencil data.
-
-Error evalData(const RawTextData &Data, const MatchFinder::MatchResult &,
- std::string *Result) {
- Result->append(Data.Text);
- return Error::success();
-}
-
-Error evalData(const DebugPrintNodeOpData &Data,
- const MatchFinder::MatchResult &Match, std::string *Result) {
- std::string Output;
- llvm::raw_string_ostream Os(Output);
- auto NodeOrErr = getNode(Match.Nodes, Data.Id);
- if (auto Err = NodeOrErr.takeError())
- return Err;
- NodeOrErr->print(Os, PrintingPolicy(Match.Context->getLangOpts()));
- *Result += Os.str();
- return Error::success();
-}
-
-Error evalData(const SelectorOpData &Data, const MatchFinder::MatchResult &Match,
- std::string *Result) {
- auto Range = Data.Selector(Match);
- if (!Range)
- return Range.takeError();
- *Result += getText(*Range, *Match.Context);
- return Error::success();
-}
-
-template <typename T>
-class StencilPartImpl : public StencilPartInterface {
- T Data;
-
-public:
- template <typename... Ps>
- explicit StencilPartImpl(Ps &&... Args)
- : StencilPartInterface(StencilPartImpl::typeId()),
- Data(std::forward<Ps>(Args)...) {}
-
- // Generates a unique identifier for this class (specifically, one per
- // instantiation of the template).
- static const void* typeId() {
- static bool b;
- return &b;
- }
-
- Error eval(const MatchFinder::MatchResult &Match,
- std::string *Result) const override {
- return evalData(Data, Match, Result);
- }
-
- bool isEqual(const StencilPartInterface &Other) const override {
- if (const auto *OtherPtr = down_cast<StencilPartImpl>(&Other))
- return isEqualData(Data, OtherPtr->Data);
- return false;
- }
-};
-
-namespace {
-using RawText = StencilPartImpl<RawTextData>;
-using DebugPrintNodeOp = StencilPartImpl<DebugPrintNodeOpData>;
-using SelectorOp = StencilPartImpl<SelectorOpData>;
-} // namespace
-
-StencilPart Stencil::wrap(StringRef Text) {
- return stencil::text(Text);
-}
-
-StencilPart Stencil::wrap(RangeSelector Selector) {
- return stencil::selection(std::move(Selector));
-}
-
-void Stencil::append(Stencil OtherStencil) {
- for (auto &Part : OtherStencil.Parts)
- Parts.push_back(std::move(Part));
-}
-
-llvm::Expected<std::string>
-Stencil::eval(const MatchFinder::MatchResult &Match) const {
- std::string Result;
- for (const auto &Part : Parts)
- if (auto Err = Part.eval(Match, &Result))
- return std::move(Err);
- return Result;
-}
-
-StencilPart stencil::text(StringRef Text) {
- return StencilPart(std::make_shared<RawText>(Text));
-}
-
-StencilPart stencil::selection(RangeSelector Selector) {
- return StencilPart(std::make_shared<SelectorOp>(std::move(Selector)));
-}
-
-StencilPart stencil::dPrint(StringRef Id) {
- return StencilPart(std::make_shared<DebugPrintNodeOp>(Id));
-}
diff --git a/lib/Tooling/Refactoring/Transformer.cpp b/lib/Tooling/Refactoring/Transformer.cpp
deleted file mode 100644
index 8e6fe6c7a940..000000000000
--- a/lib/Tooling/Refactoring/Transformer.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-//===--- Transformer.cpp - Transformer library implementation ---*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Tooling/Refactoring/Transformer.h"
-#include "clang/AST/Expr.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/ASTMatchers/ASTMatchers.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/Tooling/Refactoring/AtomicChange.h"
-#include "clang/Tooling/Refactoring/SourceCode.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/Error.h"
-#include <deque>
-#include <string>
-#include <utility>
-#include <vector>
-
-using namespace clang;
-using namespace tooling;
-
-using ast_matchers::MatchFinder;
-using ast_matchers::internal::DynTypedMatcher;
-using ast_type_traits::ASTNodeKind;
-using ast_type_traits::DynTypedNode;
-using llvm::Error;
-using llvm::StringError;
-
-using MatchResult = MatchFinder::MatchResult;
-
-// Did the text at this location originate in a macro definition (aka. body)?
-// For example,
-//
-// #define NESTED(x) x
-// #define MACRO(y) { int y = NESTED(3); }
-// if (true) MACRO(foo)
-//
-// The if statement expands to
-//
-// if (true) { int foo = 3; }
-// ^ ^
-// Loc1 Loc2
-//
-// For SourceManager SM, SM.isMacroArgExpansion(Loc1) and
-// SM.isMacroArgExpansion(Loc2) are both true, but isOriginMacroBody(sm, Loc1)
-// is false, because "foo" originated in the source file (as an argument to a
-// macro), whereas isOriginMacroBody(SM, Loc2) is true, because "3" originated
-// in the definition of MACRO.
-static bool isOriginMacroBody(const clang::SourceManager &SM,
- clang::SourceLocation Loc) {
- while (Loc.isMacroID()) {
- if (SM.isMacroBodyExpansion(Loc))
- return true;
- // Otherwise, it must be in an argument, so we continue searching up the
- // invocation stack. getImmediateMacroCallerLoc() gives the location of the
- // argument text, inside the call text.
- Loc = SM.getImmediateMacroCallerLoc(Loc);
- }
- return false;
-}
-
-Expected<SmallVector<tooling::detail::Transformation, 1>>
-tooling::detail::translateEdits(const MatchResult &Result,
- llvm::ArrayRef<ASTEdit> Edits) {
- SmallVector<tooling::detail::Transformation, 1> Transformations;
- for (const auto &Edit : Edits) {
- Expected<CharSourceRange> Range = Edit.TargetRange(Result);
- if (!Range)
- return Range.takeError();
- if (Range->isInvalid() ||
- isOriginMacroBody(*Result.SourceManager, Range->getBegin()))
- return SmallVector<Transformation, 0>();
- auto Replacement = Edit.Replacement(Result);
- if (!Replacement)
- return Replacement.takeError();
- tooling::detail::Transformation T;
- T.Range = *Range;
- T.Replacement = std::move(*Replacement);
- Transformations.push_back(std::move(T));
- }
- return Transformations;
-}
-
-ASTEdit tooling::change(RangeSelector S, TextGenerator Replacement) {
- ASTEdit E;
- E.TargetRange = std::move(S);
- E.Replacement = std::move(Replacement);
- return E;
-}
-
-RewriteRule tooling::makeRule(DynTypedMatcher M, SmallVector<ASTEdit, 1> Edits,
- TextGenerator Explanation) {
- return RewriteRule{{RewriteRule::Case{
- std::move(M), std::move(Edits), std::move(Explanation), {}}}};
-}
-
-void tooling::addInclude(RewriteRule &Rule, StringRef Header,
- IncludeFormat Format) {
- for (auto &Case : Rule.Cases)
- Case.AddedIncludes.emplace_back(Header.str(), Format);
-}
-
-// Determines whether A is a base type of B in the class hierarchy, including
-// the implicit relationship of Type and QualType.
-static bool isBaseOf(ASTNodeKind A, ASTNodeKind B) {
- static auto TypeKind = ASTNodeKind::getFromNodeKind<Type>();
- static auto QualKind = ASTNodeKind::getFromNodeKind<QualType>();
- /// Mimic the implicit conversions of Matcher<>.
- /// - From Matcher<Type> to Matcher<QualType>
- /// - From Matcher<Base> to Matcher<Derived>
- return (A.isSame(TypeKind) && B.isSame(QualKind)) || A.isBaseOf(B);
-}
-
-// Try to find a common kind to which all of the rule's matchers can be
-// converted.
-static ASTNodeKind
-findCommonKind(const SmallVectorImpl<RewriteRule::Case> &Cases) {
- assert(!Cases.empty() && "Rule must have at least one case.");
- ASTNodeKind JoinKind = Cases[0].Matcher.getSupportedKind();
- // Find a (least) Kind K, for which M.canConvertTo(K) holds, for all matchers
- // M in Rules.
- for (const auto &Case : Cases) {
- auto K = Case.Matcher.getSupportedKind();
- if (isBaseOf(JoinKind, K)) {
- JoinKind = K;
- continue;
- }
- if (K.isSame(JoinKind) || isBaseOf(K, JoinKind))
- // JoinKind is already the lowest.
- continue;
- // K and JoinKind are unrelated -- there is no least common kind.
- return ASTNodeKind();
- }
- return JoinKind;
-}
-
-// Binds each rule's matcher to a unique (and deterministic) tag based on
-// `TagBase`.
-static std::vector<DynTypedMatcher>
-taggedMatchers(StringRef TagBase,
- const SmallVectorImpl<RewriteRule::Case> &Cases) {
- std::vector<DynTypedMatcher> Matchers;
- Matchers.reserve(Cases.size());
- size_t count = 0;
- for (const auto &Case : Cases) {
- std::string Tag = (TagBase + Twine(count)).str();
- ++count;
- auto M = Case.Matcher.tryBind(Tag);
- assert(M && "RewriteRule matchers should be bindable.");
- Matchers.push_back(*std::move(M));
- }
- return Matchers;
-}
-
-// Simply gathers the contents of the various rules into a single rule. The
-// actual work to combine these into an ordered choice is deferred to matcher
-// registration.
-RewriteRule tooling::applyFirst(ArrayRef<RewriteRule> Rules) {
- RewriteRule R;
- for (auto &Rule : Rules)
- R.Cases.append(Rule.Cases.begin(), Rule.Cases.end());
- return R;
-}
-
-static DynTypedMatcher joinCaseMatchers(const RewriteRule &Rule) {
- assert(!Rule.Cases.empty() && "Rule must have at least one case.");
- if (Rule.Cases.size() == 1)
- return Rule.Cases[0].Matcher;
-
- auto CommonKind = findCommonKind(Rule.Cases);
- assert(!CommonKind.isNone() && "Cases must have compatible matchers.");
- return DynTypedMatcher::constructVariadic(
- DynTypedMatcher::VO_AnyOf, CommonKind, taggedMatchers("Tag", Rule.Cases));
-}
-
-DynTypedMatcher tooling::detail::buildMatcher(const RewriteRule &Rule) {
- DynTypedMatcher M = joinCaseMatchers(Rule);
- M.setAllowBind(true);
- // `tryBind` is guaranteed to succeed, because `AllowBind` was set to true.
- return *M.tryBind(RewriteRule::RootID);
-}
-
-// Finds the case that was "selected" -- that is, whose matcher triggered the
-// `MatchResult`.
-const RewriteRule::Case &
-tooling::detail::findSelectedCase(const MatchResult &Result,
- const RewriteRule &Rule) {
- if (Rule.Cases.size() == 1)
- return Rule.Cases[0];
-
- auto &NodesMap = Result.Nodes.getMap();
- for (size_t i = 0, N = Rule.Cases.size(); i < N; ++i) {
- std::string Tag = ("Tag" + Twine(i)).str();
- if (NodesMap.find(Tag) != NodesMap.end())
- return Rule.Cases[i];
- }
- llvm_unreachable("No tag found for this rule.");
-}
-
-constexpr llvm::StringLiteral RewriteRule::RootID;
-
-void Transformer::registerMatchers(MatchFinder *MatchFinder) {
- MatchFinder->addDynamicMatcher(tooling::detail::buildMatcher(Rule), this);
-}
-
-void Transformer::run(const MatchResult &Result) {
- if (Result.Context->getDiagnostics().hasErrorOccurred())
- return;
-
- // Verify the existence and validity of the AST node that roots this rule.
- auto &NodesMap = Result.Nodes.getMap();
- auto Root = NodesMap.find(RewriteRule::RootID);
- assert(Root != NodesMap.end() && "Transformation failed: missing root node.");
- SourceLocation RootLoc = Result.SourceManager->getExpansionLoc(
- Root->second.getSourceRange().getBegin());
- assert(RootLoc.isValid() && "Invalid location for Root node of match.");
-
- RewriteRule::Case Case = tooling::detail::findSelectedCase(Result, Rule);
- auto Transformations = tooling::detail::translateEdits(Result, Case.Edits);
- if (!Transformations) {
- Consumer(Transformations.takeError());
- return;
- }
-
- if (Transformations->empty()) {
- // No rewrite applied (but no error encountered either).
- RootLoc.print(llvm::errs() << "note: skipping match at loc ",
- *Result.SourceManager);
- llvm::errs() << "\n";
- return;
- }
-
- // Record the results in the AtomicChange.
- AtomicChange AC(*Result.SourceManager, RootLoc);
- for (const auto &T : *Transformations) {
- if (auto Err = AC.replace(*Result.SourceManager, T.Range, T.Replacement)) {
- Consumer(std::move(Err));
- return;
- }
- }
-
- for (const auto &I : Case.AddedIncludes) {
- auto &Header = I.first;
- switch (I.second) {
- case IncludeFormat::Quoted:
- AC.addHeader(Header);
- break;
- case IncludeFormat::Angled:
- AC.addHeader((llvm::Twine("<") + Header + ">").str());
- break;
- }
- }
-
- Consumer(std::move(AC));
-}
diff --git a/lib/Tooling/RefactoringCallbacks.cpp b/lib/Tooling/RefactoringCallbacks.cpp
index 2aa5b5bf9d98..919b83beb357 100644
--- a/lib/Tooling/RefactoringCallbacks.cpp
+++ b/lib/Tooling/RefactoringCallbacks.cpp
@@ -66,7 +66,7 @@ private:
};
std::unique_ptr<ASTConsumer> ASTMatchRefactorer::newASTConsumer() {
- return llvm::make_unique<RefactoringASTConsumer>(*this);
+ return std::make_unique<RefactoringASTConsumer>(*this);
}
static Replacement replaceStmtWithText(SourceManager &Sources, const Stmt &From,
diff --git a/lib/Tooling/StandaloneExecution.cpp b/lib/Tooling/StandaloneExecution.cpp
index ad82ee083a40..09094c3c23f3 100644
--- a/lib/Tooling/StandaloneExecution.cpp
+++ b/lib/Tooling/StandaloneExecution.cpp
@@ -76,7 +76,7 @@ public:
if (OptionsParser.getSourcePathList().empty())
return make_string_error(
"[StandaloneToolExecutorPlugin] No positional argument found.");
- return llvm::make_unique<StandaloneToolExecutor>(std::move(OptionsParser));
+ return std::make_unique<StandaloneToolExecutor>(std::move(OptionsParser));
}
};
diff --git a/lib/Tooling/Syntax/BuildTree.cpp b/lib/Tooling/Syntax/BuildTree.cpp
index 03c439c59e39..a0b653df133d 100644
--- a/lib/Tooling/Syntax/BuildTree.cpp
+++ b/lib/Tooling/Syntax/BuildTree.cpp
@@ -58,8 +58,11 @@ public:
/// Finish building the tree and consume the root node.
syntax::TranslationUnit *finalize() && {
auto Tokens = Arena.tokenBuffer().expandedTokens();
+ assert(!Tokens.empty());
+ assert(Tokens.back().kind() == tok::eof);
+
// Build the root of the tree, consuming all the children.
- Pending.foldChildren(Tokens,
+ Pending.foldChildren(Tokens.drop_back(),
new (Arena.allocator()) syntax::TranslationUnit);
return cast<syntax::TranslationUnit>(std::move(Pending).finalize());
@@ -96,10 +99,11 @@ private:
/// Ensures that added nodes properly nest and cover the whole token stream.
struct Forest {
Forest(syntax::Arena &A) {
- // FIXME: do not add 'eof' to the tree.
-
+ assert(!A.tokenBuffer().expandedTokens().empty());
+ assert(A.tokenBuffer().expandedTokens().back().kind() == tok::eof);
// Create all leaf nodes.
- for (auto &T : A.tokenBuffer().expandedTokens())
+ // Note that we do not have 'eof' in the tree.
+ for (auto &T : A.tokenBuffer().expandedTokens().drop_back())
Trees.insert(Trees.end(),
{&T, NodeAndRole{new (A.allocator()) syntax::Leaf(&T)}});
}
diff --git a/lib/Tooling/Syntax/Tokens.cpp b/lib/Tooling/Syntax/Tokens.cpp
index d82dc1f35c94..a2c3bc137d6b 100644
--- a/lib/Tooling/Syntax/Tokens.cpp
+++ b/lib/Tooling/Syntax/Tokens.cpp
@@ -232,6 +232,21 @@ TokenBuffer::expansionStartingAt(const syntax::Token *Spelled) const {
return E;
}
+std::vector<const syntax::Token *>
+TokenBuffer::macroExpansions(FileID FID) const {
+ auto FileIt = Files.find(FID);
+ assert(FileIt != Files.end() && "file not tracked by token buffer");
+ auto &File = FileIt->second;
+ std::vector<const syntax::Token *> Expansions;
+ auto &Spelled = File.SpelledTokens;
+ for (auto Mapping : File.Mappings) {
+ const syntax::Token *Token = &Spelled[Mapping.BeginSpelled];
+ if (Token->kind() == tok::TokenKind::identifier)
+ Expansions.push_back(Token);
+ }
+ return Expansions;
+}
+
std::vector<syntax::Token> syntax::tokenize(FileID FID, const SourceManager &SM,
const LangOptions &LO) {
std::vector<syntax::Token> Tokens;
@@ -321,7 +336,7 @@ TokenCollector::TokenCollector(Preprocessor &PP) : PP(PP) {
});
// And locations of macro calls, to properly recover boundaries of those in
// case of empty expansions.
- auto CB = llvm::make_unique<CollectPPExpansions>(*this);
+ auto CB = std::make_unique<CollectPPExpansions>(*this);
this->Collector = CB.get();
PP.addPPCallbacks(std::move(CB));
}
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index 291df0ae333d..1d6a968331b5 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -91,7 +91,34 @@ static const llvm::opt::ArgStringList *getCC1Arguments(
// We expect to get back exactly one Command job, if we didn't something
// failed. Extract that job from the Compilation.
const driver::JobList &Jobs = Compilation->getJobs();
- if (Jobs.size() != 1 || !isa<driver::Command>(*Jobs.begin())) {
+ const driver::ActionList &Actions = Compilation->getActions();
+ bool OffloadCompilation = false;
+ if (Jobs.size() > 1) {
+ for (auto A : Actions){
+ // On MacOSX real actions may end up being wrapped in BindArchAction
+ if (isa<driver::BindArchAction>(A))
+ A = *A->input_begin();
+ if (isa<driver::OffloadAction>(A)) {
+ // Offload compilation has 2 top-level actions, one (at the front) is
+ // the original host compilation and the other is offload action
+ // composed of at least one device compilation. For such case, general
+ // tooling will consider host-compilation only. For tooling on device
+ // compilation, device compilation only option, such as
+ // `--cuda-device-only`, needs specifying.
+ assert(Actions.size() > 1);
+ assert(
+ isa<driver::CompileJobAction>(Actions.front()) ||
+ // On MacOSX real actions may end up being wrapped in
+ // BindArchAction.
+ (isa<driver::BindArchAction>(Actions.front()) &&
+ isa<driver::CompileJobAction>(*Actions.front()->input_begin())));
+ OffloadCompilation = true;
+ break;
+ }
+ }
+ }
+ if (Jobs.size() == 0 || !isa<driver::Command>(*Jobs.begin()) ||
+ (Jobs.size() > 1 && !OffloadCompilation)) {
SmallString<256> error_msg;
llvm::raw_svector_ostream error_stream(error_msg);
Jobs.Print(error_stream, "; ", true);
@@ -118,20 +145,18 @@ CompilerInvocation *newInvocation(
DiagnosticsEngine *Diagnostics, const llvm::opt::ArgStringList &CC1Args) {
assert(!CC1Args.empty() && "Must at least contain the program name!");
CompilerInvocation *Invocation = new CompilerInvocation;
- CompilerInvocation::CreateFromArgs(
- *Invocation, CC1Args.data() + 1, CC1Args.data() + CC1Args.size(),
- *Diagnostics);
+ CompilerInvocation::CreateFromArgs(*Invocation, CC1Args, *Diagnostics);
Invocation->getFrontendOpts().DisableFree = false;
Invocation->getCodeGenOpts().DisableFree = false;
return Invocation;
}
-bool runToolOnCode(FrontendAction *ToolAction, const Twine &Code,
- const Twine &FileName,
+bool runToolOnCode(std::unique_ptr<FrontendAction> ToolAction,
+ const Twine &Code, const Twine &FileName,
std::shared_ptr<PCHContainerOperations> PCHContainerOps) {
- return runToolOnCodeWithArgs(ToolAction, Code, std::vector<std::string>(),
- FileName, "clang-tool",
- std::move(PCHContainerOps));
+ return runToolOnCodeWithArgs(std::move(ToolAction), Code,
+ std::vector<std::string>(), FileName,
+ "clang-tool", std::move(PCHContainerOps));
}
} // namespace tooling
@@ -153,7 +178,7 @@ namespace clang {
namespace tooling {
bool runToolOnCodeWithArgs(
- FrontendAction *ToolAction, const Twine &Code,
+ std::unique_ptr<FrontendAction> ToolAction, const Twine &Code,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
const std::vector<std::string> &Args, const Twine &FileName,
const Twine &ToolName,
@@ -166,13 +191,12 @@ bool runToolOnCodeWithArgs(
ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster();
ToolInvocation Invocation(
getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef),
- ToolAction, Files.get(),
- std::move(PCHContainerOps));
+ std::move(ToolAction), Files.get(), std::move(PCHContainerOps));
return Invocation.run();
}
bool runToolOnCodeWithArgs(
- FrontendAction *ToolAction, const Twine &Code,
+ std::unique_ptr<FrontendAction> ToolAction, const Twine &Code,
const std::vector<std::string> &Args, const Twine &FileName,
const Twine &ToolName,
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
@@ -194,8 +218,8 @@ bool runToolOnCodeWithArgs(
llvm::MemoryBuffer::getMemBuffer(FilenameWithContent.second));
}
- return runToolOnCodeWithArgs(ToolAction, Code, OverlayFileSystem, Args,
- FileName, ToolName);
+ return runToolOnCodeWithArgs(std::move(ToolAction), Code, OverlayFileSystem,
+ Args, FileName, ToolName);
}
llvm::Expected<std::string> getAbsolutePath(llvm::vfs::FileSystem &FS,
@@ -249,12 +273,15 @@ void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine,
namespace {
class SingleFrontendActionFactory : public FrontendActionFactory {
- FrontendAction *Action;
+ std::unique_ptr<FrontendAction> Action;
public:
- SingleFrontendActionFactory(FrontendAction *Action) : Action(Action) {}
+ SingleFrontendActionFactory(std::unique_ptr<FrontendAction> Action)
+ : Action(std::move(Action)) {}
- FrontendAction *create() override { return Action; }
+ std::unique_ptr<FrontendAction> create() override {
+ return std::move(Action);
+ }
};
} // namespace
@@ -266,11 +293,13 @@ ToolInvocation::ToolInvocation(
Files(Files), PCHContainerOps(std::move(PCHContainerOps)) {}
ToolInvocation::ToolInvocation(
- std::vector<std::string> CommandLine, FrontendAction *FAction,
- FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps)
+ std::vector<std::string> CommandLine,
+ std::unique_ptr<FrontendAction> FAction, FileManager *Files,
+ std::shared_ptr<PCHContainerOperations> PCHContainerOps)
: CommandLine(std::move(CommandLine)),
- Action(new SingleFrontendActionFactory(FAction)), OwnsAction(true),
- Files(Files), PCHContainerOps(std::move(PCHContainerOps)) {}
+ Action(new SingleFrontendActionFactory(std::move(FAction))),
+ OwnsAction(true), Files(Files),
+ PCHContainerOps(std::move(PCHContainerOps)) {}
ToolInvocation::~ToolInvocation() {
if (OwnsAction)
@@ -290,8 +319,7 @@ bool ToolInvocation::run() {
const char *const BinaryName = Argv[0];
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
unsigned MissingArgIndex, MissingArgCount;
- std::unique_ptr<llvm::opt::OptTable> Opts = driver::createDriverOptTable();
- llvm::opt::InputArgList ParsedArgs = Opts->ParseArgs(
+ llvm::opt::InputArgList ParsedArgs = driver::getDriverOptTable().ParseArgs(
ArrayRef<const char *>(Argv).slice(1), MissingArgIndex, MissingArgCount);
ParseDiagnosticArgs(*DiagOpts, ParsedArgs);
TextDiagnosticPrinter DiagnosticPrinter(
@@ -375,16 +403,20 @@ bool FrontendActionFactory::runInvocation(
ClangTool::ClangTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths,
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
- IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS)
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
+ IntrusiveRefCntPtr<FileManager> Files)
: Compilations(Compilations), SourcePaths(SourcePaths),
PCHContainerOps(std::move(PCHContainerOps)),
OverlayFileSystem(new llvm::vfs::OverlayFileSystem(std::move(BaseFS))),
InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem),
- Files(new FileManager(FileSystemOptions(), OverlayFileSystem)) {
+ Files(Files ? Files
+ : new FileManager(FileSystemOptions(), OverlayFileSystem)) {
OverlayFileSystem->pushOverlay(InMemoryFileSystem);
appendArgumentsAdjuster(getClangStripOutputAdjuster());
appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster());
appendArgumentsAdjuster(getClangStripDependencyFileAdjuster());
+ if (Files)
+ Files->setVirtualFileSystem(OverlayFileSystem);
}
ClangTool::~ClangTool() = default;
diff --git a/lib/Tooling/Transformer/CMakeLists.txt b/lib/Tooling/Transformer/CMakeLists.txt
new file mode 100644
index 000000000000..68f0cfeee8f6
--- /dev/null
+++ b/lib/Tooling/Transformer/CMakeLists.txt
@@ -0,0 +1,18 @@
+set(LLVM_LINK_COMPONENTS Support)
+
+add_clang_library(clangTransformer
+ RangeSelector.cpp
+ RewriteRule.cpp
+ SourceCode.cpp
+ SourceCodeBuilders.cpp
+ Stencil.cpp
+ Transformer.cpp
+
+ LINK_LIBS
+ clangAST
+ clangASTMatchers
+ clangBasic
+ clangLex
+ clangToolingCore
+ clangToolingRefactoring
+ )
diff --git a/lib/Tooling/Refactoring/RangeSelector.cpp b/lib/Tooling/Transformer/RangeSelector.cpp
index 768c02e2277b..9f81423c9022 100644
--- a/lib/Tooling/Refactoring/RangeSelector.cpp
+++ b/lib/Tooling/Transformer/RangeSelector.cpp
@@ -6,12 +6,12 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Tooling/Refactoring/RangeSelector.h"
+#include "clang/Tooling/Transformer/RangeSelector.h"
#include "clang/AST/Expr.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Lex/Lexer.h"
-#include "clang/Tooling/Refactoring/SourceCode.h"
+#include "clang/Tooling/Transformer/SourceCode.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
@@ -20,7 +20,7 @@
#include <vector>
using namespace clang;
-using namespace tooling;
+using namespace transformer;
using ast_matchers::MatchFinder;
using ast_type_traits::ASTNodeKind;
@@ -104,7 +104,7 @@ static SourceLocation findOpenParen(const CallExpr &E, const SourceManager &SM,
return findPreviousTokenKind(EndLoc, SM, LangOpts, tok::TokenKind::l_paren);
}
-RangeSelector tooling::before(RangeSelector Selector) {
+RangeSelector transformer::before(RangeSelector Selector) {
return [Selector](const MatchResult &Result) -> Expected<CharSourceRange> {
Expected<CharSourceRange> SelectedRange = Selector(Result);
if (!SelectedRange)
@@ -113,7 +113,7 @@ RangeSelector tooling::before(RangeSelector Selector) {
};
}
-RangeSelector tooling::after(RangeSelector Selector) {
+RangeSelector transformer::after(RangeSelector Selector) {
return [Selector](const MatchResult &Result) -> Expected<CharSourceRange> {
Expected<CharSourceRange> SelectedRange = Selector(Result);
if (!SelectedRange)
@@ -126,27 +126,29 @@ RangeSelector tooling::after(RangeSelector Selector) {
};
}
-RangeSelector tooling::node(std::string ID) {
+RangeSelector transformer::node(std::string ID) {
return [ID](const MatchResult &Result) -> Expected<CharSourceRange> {
Expected<DynTypedNode> Node = getNode(Result.Nodes, ID);
if (!Node)
return Node.takeError();
return Node->get<Stmt>() != nullptr && Node->get<Expr>() == nullptr
- ? getExtendedRange(*Node, tok::TokenKind::semi, *Result.Context)
+ ? tooling::getExtendedRange(*Node, tok::TokenKind::semi,
+ *Result.Context)
: CharSourceRange::getTokenRange(Node->getSourceRange());
};
}
-RangeSelector tooling::statement(std::string ID) {
+RangeSelector transformer::statement(std::string ID) {
return [ID](const MatchResult &Result) -> Expected<CharSourceRange> {
Expected<DynTypedNode> Node = getNode(Result.Nodes, ID);
if (!Node)
return Node.takeError();
- return getExtendedRange(*Node, tok::TokenKind::semi, *Result.Context);
+ return tooling::getExtendedRange(*Node, tok::TokenKind::semi,
+ *Result.Context);
};
}
-RangeSelector tooling::range(RangeSelector Begin, RangeSelector End) {
+RangeSelector transformer::range(RangeSelector Begin, RangeSelector End) {
return [Begin, End](const MatchResult &Result) -> Expected<CharSourceRange> {
Expected<CharSourceRange> BeginRange = Begin(Result);
if (!BeginRange)
@@ -165,11 +167,11 @@ RangeSelector tooling::range(RangeSelector Begin, RangeSelector End) {
};
}
-RangeSelector tooling::range(std::string BeginID, std::string EndID) {
- return tooling::range(node(std::move(BeginID)), node(std::move(EndID)));
+RangeSelector transformer::range(std::string BeginID, std::string EndID) {
+ return transformer::range(node(std::move(BeginID)), node(std::move(EndID)));
}
-RangeSelector tooling::member(std::string ID) {
+RangeSelector transformer::member(std::string ID) {
return [ID](const MatchResult &Result) -> Expected<CharSourceRange> {
Expected<DynTypedNode> Node = getNode(Result.Nodes, ID);
if (!Node)
@@ -181,7 +183,7 @@ RangeSelector tooling::member(std::string ID) {
};
}
-RangeSelector tooling::name(std::string ID) {
+RangeSelector transformer::name(std::string ID) {
return [ID](const MatchResult &Result) -> Expected<CharSourceRange> {
Expected<DynTypedNode> N = getNode(Result.Nodes, ID);
if (!N)
@@ -197,7 +199,7 @@ RangeSelector tooling::name(std::string ID) {
// `foo<int>` for which this range will be too short. Doing so will
// require subcasing `NamedDecl`, because it doesn't provide virtual
// access to the \c DeclarationNameInfo.
- if (getText(R, *Result.Context) != D->getName())
+ if (tooling::getText(R, *Result.Context) != D->getName())
return CharSourceRange();
return R;
}
@@ -219,6 +221,9 @@ RangeSelector tooling::name(std::string ID) {
}
namespace {
+// FIXME: make this available in the public API for users to easily create their
+// own selectors.
+
// Creates a selector from a range-selection function \p Func, which selects a
// range that is relative to a bound node id. \c T is the node type expected by
// \p Func.
@@ -253,7 +258,7 @@ CharSourceRange getStatementsRange(const MatchResult &,
}
} // namespace
-RangeSelector tooling::statements(std::string ID) {
+RangeSelector transformer::statements(std::string ID) {
return RelativeSelector<CompoundStmt, getStatementsRange>(std::move(ID));
}
@@ -268,7 +273,7 @@ CharSourceRange getCallArgumentsRange(const MatchResult &Result,
}
} // namespace
-RangeSelector tooling::callArgs(std::string ID) {
+RangeSelector transformer::callArgs(std::string ID) {
return RelativeSelector<CallExpr, getCallArgumentsRange>(std::move(ID));
}
@@ -282,11 +287,24 @@ CharSourceRange getElementsRange(const MatchResult &,
}
} // namespace
-RangeSelector tooling::initListElements(std::string ID) {
+RangeSelector transformer::initListElements(std::string ID) {
return RelativeSelector<InitListExpr, getElementsRange>(std::move(ID));
}
-RangeSelector tooling::expansion(RangeSelector S) {
+namespace {
+// Returns the range of the else branch, including the `else` keyword.
+CharSourceRange getElseRange(const MatchResult &Result, const IfStmt &S) {
+ return tooling::maybeExtendRange(
+ CharSourceRange::getTokenRange(S.getElseLoc(), S.getEndLoc()),
+ tok::TokenKind::semi, *Result.Context);
+}
+} // namespace
+
+RangeSelector transformer::elseBranch(std::string ID) {
+ return RelativeSelector<IfStmt, getElseRange>(std::move(ID));
+}
+
+RangeSelector transformer::expansion(RangeSelector S) {
return [S](const MatchResult &Result) -> Expected<CharSourceRange> {
Expected<CharSourceRange> SRange = S(Result);
if (!SRange)
diff --git a/lib/Tooling/Transformer/RewriteRule.cpp b/lib/Tooling/Transformer/RewriteRule.cpp
new file mode 100644
index 000000000000..6fa558f7b2ee
--- /dev/null
+++ b/lib/Tooling/Transformer/RewriteRule.cpp
@@ -0,0 +1,178 @@
+//===--- Transformer.cpp - Transformer library implementation ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Transformer/RewriteRule.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Transformer/SourceCode.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace clang;
+using namespace transformer;
+
+using ast_matchers::MatchFinder;
+using ast_matchers::internal::DynTypedMatcher;
+using ast_type_traits::ASTNodeKind;
+
+using MatchResult = MatchFinder::MatchResult;
+
+Expected<SmallVector<transformer::detail::Transformation, 1>>
+transformer::detail::translateEdits(const MatchResult &Result,
+ llvm::ArrayRef<ASTEdit> Edits) {
+ SmallVector<transformer::detail::Transformation, 1> Transformations;
+ for (const auto &Edit : Edits) {
+ Expected<CharSourceRange> Range = Edit.TargetRange(Result);
+ if (!Range)
+ return Range.takeError();
+ llvm::Optional<CharSourceRange> EditRange =
+ tooling::getRangeForEdit(*Range, *Result.Context);
+ // FIXME: let user specify whether to treat this case as an error or ignore
+ // it as is currently done.
+ if (!EditRange)
+ return SmallVector<Transformation, 0>();
+ auto Replacement = Edit.Replacement(Result);
+ if (!Replacement)
+ return Replacement.takeError();
+ transformer::detail::Transformation T;
+ T.Range = *EditRange;
+ T.Replacement = std::move(*Replacement);
+ Transformations.push_back(std::move(T));
+ }
+ return Transformations;
+}
+
+ASTEdit transformer::change(RangeSelector S, TextGenerator Replacement) {
+ ASTEdit E;
+ E.TargetRange = std::move(S);
+ E.Replacement = std::move(Replacement);
+ return E;
+}
+
+RewriteRule transformer::makeRule(DynTypedMatcher M, SmallVector<ASTEdit, 1> Edits,
+ TextGenerator Explanation) {
+ return RewriteRule{{RewriteRule::Case{
+ std::move(M), std::move(Edits), std::move(Explanation), {}}}};
+}
+
+void transformer::addInclude(RewriteRule &Rule, StringRef Header,
+ IncludeFormat Format) {
+ for (auto &Case : Rule.Cases)
+ Case.AddedIncludes.emplace_back(Header.str(), Format);
+}
+
+#ifndef NDEBUG
+// Filters for supported matcher kinds. FIXME: Explicitly list the allowed kinds
+// (all node matcher types except for `QualType` and `Type`), rather than just
+// banning `QualType` and `Type`.
+static bool hasValidKind(const DynTypedMatcher &M) {
+ return !M.canConvertTo<QualType>();
+}
+#endif
+
+// Binds each rule's matcher to a unique (and deterministic) tag based on
+// `TagBase` and the id paired with the case.
+static std::vector<DynTypedMatcher> taggedMatchers(
+ StringRef TagBase,
+ const SmallVectorImpl<std::pair<size_t, RewriteRule::Case>> &Cases) {
+ std::vector<DynTypedMatcher> Matchers;
+ Matchers.reserve(Cases.size());
+ for (const auto &Case : Cases) {
+ std::string Tag = (TagBase + Twine(Case.first)).str();
+ // HACK: Many matchers are not bindable, so ensure that tryBind will work.
+ DynTypedMatcher BoundMatcher(Case.second.Matcher);
+ BoundMatcher.setAllowBind(true);
+ auto M = BoundMatcher.tryBind(Tag);
+ Matchers.push_back(*std::move(M));
+ }
+ return Matchers;
+}
+
+// Simply gathers the contents of the various rules into a single rule. The
+// actual work to combine these into an ordered choice is deferred to matcher
+// registration.
+RewriteRule transformer::applyFirst(ArrayRef<RewriteRule> Rules) {
+ RewriteRule R;
+ for (auto &Rule : Rules)
+ R.Cases.append(Rule.Cases.begin(), Rule.Cases.end());
+ return R;
+}
+
+std::vector<DynTypedMatcher>
+transformer::detail::buildMatchers(const RewriteRule &Rule) {
+ // Map the cases into buckets of matchers -- one for each "root" AST kind,
+ // which guarantees that they can be combined in a single anyOf matcher. Each
+ // case is paired with an identifying number that is converted to a string id
+ // in `taggedMatchers`.
+ std::map<ASTNodeKind, SmallVector<std::pair<size_t, RewriteRule::Case>, 1>>
+ Buckets;
+ const SmallVectorImpl<RewriteRule::Case> &Cases = Rule.Cases;
+ for (int I = 0, N = Cases.size(); I < N; ++I) {
+ assert(hasValidKind(Cases[I].Matcher) &&
+ "Matcher must be non-(Qual)Type node matcher");
+ Buckets[Cases[I].Matcher.getSupportedKind()].emplace_back(I, Cases[I]);
+ }
+
+ std::vector<DynTypedMatcher> Matchers;
+ for (const auto &Bucket : Buckets) {
+ DynTypedMatcher M = DynTypedMatcher::constructVariadic(
+ DynTypedMatcher::VO_AnyOf, Bucket.first,
+ taggedMatchers("Tag", Bucket.second));
+ M.setAllowBind(true);
+ // `tryBind` is guaranteed to succeed, because `AllowBind` was set to true.
+ Matchers.push_back(*M.tryBind(RewriteRule::RootID));
+ }
+ return Matchers;
+}
+
+DynTypedMatcher transformer::detail::buildMatcher(const RewriteRule &Rule) {
+ std::vector<DynTypedMatcher> Ms = buildMatchers(Rule);
+ assert(Ms.size() == 1 && "Cases must have compatible matchers.");
+ return Ms[0];
+}
+
+SourceLocation transformer::detail::getRuleMatchLoc(const MatchResult &Result) {
+ auto &NodesMap = Result.Nodes.getMap();
+ auto Root = NodesMap.find(RewriteRule::RootID);
+ assert(Root != NodesMap.end() && "Transformation failed: missing root node.");
+ llvm::Optional<CharSourceRange> RootRange = tooling::getRangeForEdit(
+ CharSourceRange::getTokenRange(Root->second.getSourceRange()),
+ *Result.Context);
+ if (RootRange)
+ return RootRange->getBegin();
+ // The match doesn't have a coherent range, so fall back to the expansion
+ // location as the "beginning" of the match.
+ return Result.SourceManager->getExpansionLoc(
+ Root->second.getSourceRange().getBegin());
+}
+
+// Finds the case that was "selected" -- that is, whose matcher triggered the
+// `MatchResult`.
+const RewriteRule::Case &
+transformer::detail::findSelectedCase(const MatchResult &Result,
+ const RewriteRule &Rule) {
+ if (Rule.Cases.size() == 1)
+ return Rule.Cases[0];
+
+ auto &NodesMap = Result.Nodes.getMap();
+ for (size_t i = 0, N = Rule.Cases.size(); i < N; ++i) {
+ std::string Tag = ("Tag" + Twine(i)).str();
+ if (NodesMap.find(Tag) != NodesMap.end())
+ return Rule.Cases[i];
+ }
+ llvm_unreachable("No tag found for this rule.");
+}
+
+constexpr llvm::StringLiteral RewriteRule::RootID;
diff --git a/lib/Tooling/Transformer/SourceCode.cpp b/lib/Tooling/Transformer/SourceCode.cpp
new file mode 100644
index 000000000000..836401d1e605
--- /dev/null
+++ b/lib/Tooling/Transformer/SourceCode.cpp
@@ -0,0 +1,65 @@
+//===--- SourceCode.cpp - Source code manipulation routines -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides functions that simplify extraction of source code.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Tooling/Transformer/SourceCode.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang;
+
+StringRef clang::tooling::getText(CharSourceRange Range,
+ const ASTContext &Context) {
+ return Lexer::getSourceText(Range, Context.getSourceManager(),
+ Context.getLangOpts());
+}
+
+CharSourceRange clang::tooling::maybeExtendRange(CharSourceRange Range,
+ tok::TokenKind Next,
+ ASTContext &Context) {
+ Optional<Token> Tok = Lexer::findNextToken(
+ Range.getEnd(), Context.getSourceManager(), Context.getLangOpts());
+ if (!Tok || !Tok->is(Next))
+ return Range;
+ return CharSourceRange::getTokenRange(Range.getBegin(), Tok->getLocation());
+}
+
+llvm::Optional<CharSourceRange>
+clang::tooling::getRangeForEdit(const CharSourceRange &EditRange,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ // FIXME: makeFileCharRange() has the disadvantage of stripping off "identity"
+ // macros. For example, if we're looking to rewrite the int literal 3 to 6,
+ // and we have the following definition:
+ // #define DO_NOTHING(x) x
+ // then
+ // foo(DO_NOTHING(3))
+ // will be rewritten to
+ // foo(6)
+ // rather than the arguably better
+ // foo(DO_NOTHING(6))
+ // Decide whether the current behavior is desirable and modify if not.
+ CharSourceRange Range = Lexer::makeFileCharRange(EditRange, SM, LangOpts);
+ if (Range.isInvalid())
+ return None;
+
+ if (Range.getBegin().isMacroID() || Range.getEnd().isMacroID())
+ return None;
+ if (SM.isInSystemHeader(Range.getBegin()) ||
+ SM.isInSystemHeader(Range.getEnd()))
+ return None;
+
+ 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 None;
+
+ return Range;
+}
diff --git a/lib/Tooling/Transformer/SourceCodeBuilders.cpp b/lib/Tooling/Transformer/SourceCodeBuilders.cpp
new file mode 100644
index 000000000000..56ec45e8fd1d
--- /dev/null
+++ b/lib/Tooling/Transformer/SourceCodeBuilders.cpp
@@ -0,0 +1,160 @@
+//===--- SourceCodeBuilder.cpp ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Transformer/SourceCodeBuilders.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Tooling/Transformer/SourceCode.h"
+#include "llvm/ADT/Twine.h"
+#include <string>
+
+using namespace clang;
+using namespace tooling;
+
+const Expr *tooling::reallyIgnoreImplicit(const Expr &E) {
+ const Expr *Expr = E.IgnoreImplicit();
+ if (const auto *CE = dyn_cast<CXXConstructExpr>(Expr)) {
+ if (CE->getNumArgs() > 0 &&
+ CE->getArg(0)->getSourceRange() == Expr->getSourceRange())
+ return CE->getArg(0)->IgnoreImplicit();
+ }
+ return Expr;
+}
+
+bool tooling::mayEverNeedParens(const Expr &E) {
+ const Expr *Expr = reallyIgnoreImplicit(E);
+ // We always want parens around unary, binary, and ternary operators, because
+ // they are lower precedence.
+ if (isa<UnaryOperator>(Expr) || isa<BinaryOperator>(Expr) ||
+ isa<AbstractConditionalOperator>(Expr))
+ return true;
+
+ // We need parens around calls to all overloaded operators except: function
+ // calls, subscripts, and expressions that are already part of an (implicit)
+ // call to operator->. These latter are all in the same precedence level as
+ // dot/arrow and that level is left associative, so they don't need parens
+ // when appearing on the left.
+ if (const auto *Op = dyn_cast<CXXOperatorCallExpr>(Expr))
+ return Op->getOperator() != OO_Call && Op->getOperator() != OO_Subscript &&
+ Op->getOperator() != OO_Arrow;
+
+ return false;
+}
+
+bool tooling::needParensAfterUnaryOperator(const Expr &E) {
+ const Expr *Expr = reallyIgnoreImplicit(E);
+ if (isa<BinaryOperator>(Expr) || isa<AbstractConditionalOperator>(Expr))
+ return true;
+
+ if (const auto *Op = dyn_cast<CXXOperatorCallExpr>(Expr))
+ return Op->getNumArgs() == 2 && Op->getOperator() != OO_PlusPlus &&
+ Op->getOperator() != OO_MinusMinus && Op->getOperator() != OO_Call &&
+ Op->getOperator() != OO_Subscript;
+
+ return false;
+}
+
+llvm::Optional<std::string> tooling::buildParens(const Expr &E,
+ const ASTContext &Context) {
+ StringRef Text = getText(E, Context);
+ if (Text.empty())
+ return llvm::None;
+ if (mayEverNeedParens(E))
+ return ("(" + Text + ")").str();
+ return Text.str();
+}
+
+llvm::Optional<std::string>
+tooling::buildDereference(const Expr &E, const ASTContext &Context) {
+ if (const auto *Op = dyn_cast<UnaryOperator>(&E))
+ if (Op->getOpcode() == UO_AddrOf) {
+ // Strip leading '&'.
+ StringRef Text =
+ getText(*Op->getSubExpr()->IgnoreParenImpCasts(), Context);
+ if (Text.empty())
+ return llvm::None;
+ return Text.str();
+ }
+
+ StringRef Text = getText(E, Context);
+ if (Text.empty())
+ return llvm::None;
+ // Add leading '*'.
+ if (needParensAfterUnaryOperator(E))
+ return ("*(" + Text + ")").str();
+ return ("*" + Text).str();
+}
+
+llvm::Optional<std::string> tooling::buildAddressOf(const Expr &E,
+ const ASTContext &Context) {
+ if (const auto *Op = dyn_cast<UnaryOperator>(&E))
+ if (Op->getOpcode() == UO_Deref) {
+ // Strip leading '*'.
+ StringRef Text =
+ getText(*Op->getSubExpr()->IgnoreParenImpCasts(), Context);
+ if (Text.empty())
+ return llvm::None;
+ return Text.str();
+ }
+ // Add leading '&'.
+ StringRef Text = getText(E, Context);
+ if (Text.empty())
+ return llvm::None;
+ if (needParensAfterUnaryOperator(E)) {
+ return ("&(" + Text + ")").str();
+ }
+ return ("&" + Text).str();
+}
+
+llvm::Optional<std::string> tooling::buildDot(const Expr &E,
+ const ASTContext &Context) {
+ if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E))
+ if (Op->getOpcode() == UO_Deref) {
+ // Strip leading '*', add following '->'.
+ const Expr *SubExpr = Op->getSubExpr()->IgnoreParenImpCasts();
+ StringRef DerefText = getText(*SubExpr, Context);
+ if (DerefText.empty())
+ return llvm::None;
+ if (needParensBeforeDotOrArrow(*SubExpr))
+ return ("(" + DerefText + ")->").str();
+ return (DerefText + "->").str();
+ }
+
+ // Add following '.'.
+ StringRef Text = getText(E, Context);
+ if (Text.empty())
+ return llvm::None;
+ if (needParensBeforeDotOrArrow(E)) {
+ return ("(" + Text + ").").str();
+ }
+ return (Text + ".").str();
+}
+
+llvm::Optional<std::string> tooling::buildArrow(const Expr &E,
+ const ASTContext &Context) {
+ if (const auto *Op = llvm::dyn_cast<UnaryOperator>(&E))
+ if (Op->getOpcode() == UO_AddrOf) {
+ // Strip leading '&', add following '.'.
+ const Expr *SubExpr = Op->getSubExpr()->IgnoreParenImpCasts();
+ StringRef DerefText = getText(*SubExpr, Context);
+ if (DerefText.empty())
+ return llvm::None;
+ if (needParensBeforeDotOrArrow(*SubExpr))
+ return ("(" + DerefText + ").").str();
+ return (DerefText + ".").str();
+ }
+
+ // Add following '->'.
+ StringRef Text = getText(E, Context);
+ if (Text.empty())
+ return llvm::None;
+ if (needParensBeforeDotOrArrow(E))
+ return ("(" + Text + ")->").str();
+ return (Text + "->").str();
+}
diff --git a/lib/Tooling/Transformer/Stencil.cpp b/lib/Tooling/Transformer/Stencil.cpp
new file mode 100644
index 000000000000..984950a54e96
--- /dev/null
+++ b/lib/Tooling/Transformer/Stencil.cpp
@@ -0,0 +1,318 @@
+//===--- Stencil.cpp - Stencil implementation -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Transformer/Stencil.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/Expr.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/Transformer/SourceCode.h"
+#include "clang/Tooling/Transformer/SourceCodeBuilders.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Errc.h"
+#include <atomic>
+#include <memory>
+#include <string>
+
+using namespace clang;
+using namespace transformer;
+
+using ast_matchers::MatchFinder;
+using ast_type_traits::DynTypedNode;
+using llvm::errc;
+using llvm::Error;
+using llvm::Expected;
+using llvm::StringError;
+
+static llvm::Expected<DynTypedNode>
+getNode(const ast_matchers::BoundNodes &Nodes, StringRef Id) {
+ auto &NodesMap = Nodes.getMap();
+ auto It = NodesMap.find(Id);
+ if (It == NodesMap.end())
+ return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument,
+ "Id not bound: " + Id);
+ return It->second;
+}
+
+namespace {
+// An arbitrary fragment of code within a stencil.
+struct RawTextData {
+ explicit RawTextData(std::string T) : Text(std::move(T)) {}
+ std::string Text;
+};
+
+// A debugging operation to dump the AST for a particular (bound) AST node.
+struct DebugPrintNodeData {
+ explicit DebugPrintNodeData(std::string S) : Id(std::move(S)) {}
+ std::string Id;
+};
+
+// Operators that take a single node Id as an argument.
+enum class UnaryNodeOperator {
+ Parens,
+ Deref,
+ Address,
+};
+
+// Generic container for stencil operations with a (single) node-id argument.
+struct UnaryOperationData {
+ UnaryOperationData(UnaryNodeOperator Op, std::string Id)
+ : Op(Op), Id(std::move(Id)) {}
+ UnaryNodeOperator Op;
+ std::string Id;
+};
+
+// The fragment of code corresponding to the selected range.
+struct SelectorData {
+ explicit SelectorData(RangeSelector S) : Selector(std::move(S)) {}
+ RangeSelector Selector;
+};
+
+// A stencil operation to build a member access `e.m` or `e->m`, as appropriate.
+struct AccessData {
+ AccessData(StringRef BaseId, StencilPart Member)
+ : BaseId(BaseId), Member(std::move(Member)) {}
+ std::string BaseId;
+ StencilPart Member;
+};
+
+struct IfBoundData {
+ IfBoundData(StringRef Id, StencilPart TruePart, StencilPart FalsePart)
+ : Id(Id), TruePart(std::move(TruePart)), FalsePart(std::move(FalsePart)) {
+ }
+ std::string Id;
+ StencilPart TruePart;
+ StencilPart FalsePart;
+};
+
+std::string toStringData(const RawTextData &Data) {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ OS << "\"";
+ OS.write_escaped(Data.Text);
+ OS << "\"";
+ OS.flush();
+ return Result;
+}
+
+std::string toStringData(const DebugPrintNodeData &Data) {
+ return (llvm::Twine("dPrint(\"") + Data.Id + "\")").str();
+}
+
+std::string toStringData(const UnaryOperationData &Data) {
+ StringRef OpName;
+ switch (Data.Op) {
+ case UnaryNodeOperator::Parens:
+ OpName = "expression";
+ break;
+ case UnaryNodeOperator::Deref:
+ OpName = "deref";
+ break;
+ case UnaryNodeOperator::Address:
+ OpName = "addressOf";
+ break;
+ }
+ return (OpName + "(\"" + Data.Id + "\")").str();
+}
+
+std::string toStringData(const SelectorData &) { return "selection(...)"; }
+
+std::string toStringData(const AccessData &Data) {
+ return (llvm::Twine("access(\"") + Data.BaseId + "\", " +
+ Data.Member.toString() + ")")
+ .str();
+}
+
+std::string toStringData(const IfBoundData &Data) {
+ return (llvm::Twine("ifBound(\"") + Data.Id + "\", " +
+ Data.TruePart.toString() + ", " + Data.FalsePart.toString() + ")")
+ .str();
+}
+
+std::string toStringData(const MatchConsumer<std::string> &) {
+ return "run(...)";
+}
+
+// The `evalData()` overloads evaluate the given stencil data to a string, given
+// the match result, and append it to `Result`. We define an overload for each
+// type of stencil data.
+
+Error evalData(const RawTextData &Data, const MatchFinder::MatchResult &,
+ std::string *Result) {
+ Result->append(Data.Text);
+ return Error::success();
+}
+
+Error evalData(const DebugPrintNodeData &Data,
+ const MatchFinder::MatchResult &Match, std::string *Result) {
+ std::string Output;
+ llvm::raw_string_ostream Os(Output);
+ auto NodeOrErr = getNode(Match.Nodes, Data.Id);
+ if (auto Err = NodeOrErr.takeError())
+ return Err;
+ NodeOrErr->print(Os, PrintingPolicy(Match.Context->getLangOpts()));
+ *Result += Os.str();
+ return Error::success();
+}
+
+Error evalData(const UnaryOperationData &Data,
+ const MatchFinder::MatchResult &Match, std::string *Result) {
+ const auto *E = Match.Nodes.getNodeAs<Expr>(Data.Id);
+ if (E == nullptr)
+ return llvm::make_error<StringError>(
+ errc::invalid_argument, "Id not bound or not Expr: " + Data.Id);
+ llvm::Optional<std::string> Source;
+ switch (Data.Op) {
+ case UnaryNodeOperator::Parens:
+ Source = tooling::buildParens(*E, *Match.Context);
+ break;
+ case UnaryNodeOperator::Deref:
+ Source = tooling::buildDereference(*E, *Match.Context);
+ break;
+ case UnaryNodeOperator::Address:
+ Source = tooling::buildAddressOf(*E, *Match.Context);
+ break;
+ }
+ if (!Source)
+ return llvm::make_error<StringError>(
+ errc::invalid_argument,
+ "Could not construct expression source from ID: " + Data.Id);
+ *Result += *Source;
+ return Error::success();
+}
+
+Error evalData(const SelectorData &Data, const MatchFinder::MatchResult &Match,
+ std::string *Result) {
+ auto Range = Data.Selector(Match);
+ if (!Range)
+ return Range.takeError();
+ *Result += tooling::getText(*Range, *Match.Context);
+ return Error::success();
+}
+
+Error evalData(const AccessData &Data, const MatchFinder::MatchResult &Match,
+ std::string *Result) {
+ const auto *E = Match.Nodes.getNodeAs<Expr>(Data.BaseId);
+ if (E == nullptr)
+ return llvm::make_error<StringError>(errc::invalid_argument,
+ "Id not bound: " + Data.BaseId);
+ if (!E->isImplicitCXXThis()) {
+ if (llvm::Optional<std::string> S =
+ E->getType()->isAnyPointerType()
+ ? tooling::buildArrow(*E, *Match.Context)
+ : tooling::buildDot(*E, *Match.Context))
+ *Result += *S;
+ else
+ return llvm::make_error<StringError>(
+ errc::invalid_argument,
+ "Could not construct object text from ID: " + Data.BaseId);
+ }
+ return Data.Member.eval(Match, Result);
+}
+
+Error evalData(const IfBoundData &Data, const MatchFinder::MatchResult &Match,
+ std::string *Result) {
+ auto &M = Match.Nodes.getMap();
+ return (M.find(Data.Id) != M.end() ? Data.TruePart : Data.FalsePart)
+ .eval(Match, Result);
+}
+
+Error evalData(const MatchConsumer<std::string> &Fn,
+ const MatchFinder::MatchResult &Match, std::string *Result) {
+ Expected<std::string> Value = Fn(Match);
+ if (!Value)
+ return Value.takeError();
+ *Result += *Value;
+ return Error::success();
+}
+
+template <typename T>
+class StencilPartImpl : public StencilPartInterface {
+ T Data;
+
+public:
+ template <typename... Ps>
+ explicit StencilPartImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {}
+
+ Error eval(const MatchFinder::MatchResult &Match,
+ std::string *Result) const override {
+ return evalData(Data, Match, Result);
+ }
+
+ std::string toString() const override { return toStringData(Data); }
+};
+} // namespace
+
+StencilPart Stencil::wrap(StringRef Text) {
+ return transformer::text(Text);
+}
+
+StencilPart Stencil::wrap(RangeSelector Selector) {
+ return transformer::selection(std::move(Selector));
+}
+
+void Stencil::append(Stencil OtherStencil) {
+ for (auto &Part : OtherStencil.Parts)
+ Parts.push_back(std::move(Part));
+}
+
+llvm::Expected<std::string>
+Stencil::eval(const MatchFinder::MatchResult &Match) const {
+ std::string Result;
+ for (const auto &Part : Parts)
+ if (auto Err = Part.eval(Match, &Result))
+ return std::move(Err);
+ return Result;
+}
+
+StencilPart transformer::text(StringRef Text) {
+ return StencilPart(std::make_shared<StencilPartImpl<RawTextData>>(Text));
+}
+
+StencilPart transformer::selection(RangeSelector Selector) {
+ return StencilPart(
+ std::make_shared<StencilPartImpl<SelectorData>>(std::move(Selector)));
+}
+
+StencilPart transformer::dPrint(StringRef Id) {
+ return StencilPart(std::make_shared<StencilPartImpl<DebugPrintNodeData>>(Id));
+}
+
+StencilPart transformer::expression(llvm::StringRef Id) {
+ return StencilPart(std::make_shared<StencilPartImpl<UnaryOperationData>>(
+ UnaryNodeOperator::Parens, Id));
+}
+
+StencilPart transformer::deref(llvm::StringRef ExprId) {
+ return StencilPart(std::make_shared<StencilPartImpl<UnaryOperationData>>(
+ UnaryNodeOperator::Deref, ExprId));
+}
+
+StencilPart transformer::addressOf(llvm::StringRef ExprId) {
+ return StencilPart(std::make_shared<StencilPartImpl<UnaryOperationData>>(
+ UnaryNodeOperator::Address, ExprId));
+}
+
+StencilPart transformer::access(StringRef BaseId, StencilPart Member) {
+ return StencilPart(
+ std::make_shared<StencilPartImpl<AccessData>>(BaseId, std::move(Member)));
+}
+
+StencilPart transformer::ifBound(StringRef Id, StencilPart TruePart,
+ StencilPart FalsePart) {
+ return StencilPart(std::make_shared<StencilPartImpl<IfBoundData>>(
+ Id, std::move(TruePart), std::move(FalsePart)));
+}
+
+StencilPart transformer::run(MatchConsumer<std::string> Fn) {
+ return StencilPart(
+ std::make_shared<StencilPartImpl<MatchConsumer<std::string>>>(
+ std::move(Fn)));
+}
diff --git a/lib/Tooling/Transformer/Transformer.cpp b/lib/Tooling/Transformer/Transformer.cpp
new file mode 100644
index 000000000000..71f0646f4c0e
--- /dev/null
+++ b/lib/Tooling/Transformer/Transformer.cpp
@@ -0,0 +1,72 @@
+//===--- Transformer.cpp - Transformer library implementation ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/Transformer/Transformer.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "llvm/Support/Error.h"
+#include <utility>
+#include <vector>
+
+using namespace clang;
+using namespace tooling;
+
+using ast_matchers::MatchFinder;
+
+void Transformer::registerMatchers(MatchFinder *MatchFinder) {
+ for (auto &Matcher : transformer::detail::buildMatchers(Rule))
+ MatchFinder->addDynamicMatcher(Matcher, this);
+}
+
+void Transformer::run(const MatchFinder::MatchResult &Result) {
+ if (Result.Context->getDiagnostics().hasErrorOccurred())
+ return;
+
+ transformer::RewriteRule::Case Case =
+ transformer::detail::findSelectedCase(Result, Rule);
+ auto Transformations = transformer::detail::translateEdits(Result, Case.Edits);
+ if (!Transformations) {
+ Consumer(Transformations.takeError());
+ return;
+ }
+
+ if (Transformations->empty()) {
+ // No rewrite applied (but no error encountered either).
+ transformer::detail::getRuleMatchLoc(Result).print(
+ llvm::errs() << "note: skipping match at loc ", *Result.SourceManager);
+ llvm::errs() << "\n";
+ return;
+ }
+
+ // Record the results in the AtomicChange, anchored at the location of the
+ // first change.
+ AtomicChange AC(*Result.SourceManager,
+ (*Transformations)[0].Range.getBegin());
+ for (const auto &T : *Transformations) {
+ if (auto Err = AC.replace(*Result.SourceManager, T.Range, T.Replacement)) {
+ Consumer(std::move(Err));
+ return;
+ }
+ }
+
+ for (const auto &I : Case.AddedIncludes) {
+ auto &Header = I.first;
+ switch (I.second) {
+ case transformer::IncludeFormat::Quoted:
+ AC.addHeader(Header);
+ break;
+ case transformer::IncludeFormat::Angled:
+ AC.addHeader((llvm::Twine("<") + Header + ">").str());
+ break;
+ }
+ }
+
+ Consumer(std::move(AC));
+}
diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp
index 60a7feb7119b..f39c18bae3ff 100644
--- a/tools/clang-format/ClangFormat.cpp
+++ b/tools/clang-format/ClangFormat.cpp
@@ -18,6 +18,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
#include "clang/Format/Format.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
@@ -51,13 +52,14 @@ static cl::list<unsigned>
"Can only be used with one input file."),
cl::cat(ClangFormatCategory));
static cl::list<std::string>
-LineRanges("lines", cl::desc("<start line>:<end line> - format a range of\n"
- "lines (both 1-based).\n"
- "Multiple ranges can be formatted by specifying\n"
- "several -lines arguments.\n"
- "Can't be used with -offset and -length.\n"
- "Can only be used with one input file."),
- cl::cat(ClangFormatCategory));
+ LineRanges("lines",
+ cl::desc("<start line>:<end line> - format a range of\n"
+ "lines (both 1-based).\n"
+ "Multiple ranges can be formatted by specifying\n"
+ "several -lines arguments.\n"
+ "Can't be used with -offset and -length.\n"
+ "Can only be used with one input file."),
+ cl::cat(ClangFormatCategory));
static cl::opt<std::string>
Style("style", cl::desc(clang::format::StyleOptionHelpDescription),
cl::init(clang::format::DefaultFormatStyle),
@@ -72,12 +74,12 @@ static cl::opt<std::string>
cl::init(clang::format::DefaultFallbackStyle),
cl::cat(ClangFormatCategory));
-static cl::opt<std::string>
-AssumeFileName("assume-filename",
- cl::desc("When reading from stdin, clang-format assumes this\n"
- "filename to look for a style config file (with\n"
- "-style=file) and to determine the language."),
- cl::init("<stdin>"), cl::cat(ClangFormatCategory));
+static cl::opt<std::string> AssumeFileName(
+ "assume-filename",
+ cl::desc("When reading from stdin, clang-format assumes this\n"
+ "filename to look for a style config file (with\n"
+ "-style=file) and to determine the language."),
+ cl::init("<stdin>"), cl::cat(ClangFormatCategory));
static cl::opt<bool> Inplace("i",
cl::desc("Inplace edit <file>s, if specified."),
@@ -107,6 +109,54 @@ static cl::opt<bool>
Verbose("verbose", cl::desc("If set, shows the list of processed files"),
cl::cat(ClangFormatCategory));
+// Use --dry-run to match other LLVM tools when you mean do it but don't
+// actually do it
+static cl::opt<bool>
+ DryRun("dry-run",
+ cl::desc("If set, do not actually make the formatting changes"),
+ cl::cat(ClangFormatCategory));
+
+// Use -n as a common command as an alias for --dry-run. (git and make use -n)
+static cl::alias DryRunShort("n", cl::desc("Alias for --dry-run"),
+ cl::cat(ClangFormatCategory), cl::aliasopt(DryRun),
+ cl::NotHidden);
+
+// Emulate being able to turn on/off the warning.
+static cl::opt<bool>
+ WarnFormat("Wclang-format-violations",
+ cl::desc("Warnings about individual formatting changes needed. "
+ "Used only with --dry-run or -n"),
+ cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden);
+
+static cl::opt<bool>
+ NoWarnFormat("Wno-clang-format-violations",
+ cl::desc("Do not warn about individual formatting changes "
+ "needed. Used only with --dry-run or -n"),
+ cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden);
+
+static cl::opt<unsigned> ErrorLimit(
+ "ferror-limit",
+ cl::desc("Set the maximum number of clang-format errors to emit before "
+ "stopping (0 = no limit). Used only with --dry-run or -n"),
+ cl::init(0), cl::cat(ClangFormatCategory));
+
+static cl::opt<bool>
+ WarningsAsErrors("Werror",
+ cl::desc("If set, changes formatting warnings to errors"),
+ cl::cat(ClangFormatCategory));
+
+static cl::opt<bool>
+ ShowColors("fcolor-diagnostics",
+ cl::desc("If set, and on a color-capable terminal controls "
+ "whether or not to print diagnostics in color"),
+ cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden);
+
+static cl::opt<bool>
+ NoShowColors("fno-color-diagnostics",
+ cl::desc("If set, and on a color-capable terminal controls "
+ "whether or not to print diagnostics in color"),
+ cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden);
+
static cl::list<std::string> FileNames(cl::Positional, cl::desc("[<file> ...]"),
cl::cat(ClangFormatCategory));
@@ -117,7 +167,8 @@ static FileID createInMemoryFile(StringRef FileName, MemoryBuffer *Source,
SourceManager &Sources, FileManager &Files,
llvm::vfs::InMemoryFileSystem *MemFS) {
MemFS->addFileNoOwn(FileName, 0, Source);
- return Sources.createFileID(Files.getFile(FileName), SourceLocation(),
+ auto File = Files.getFile(FileName);
+ return Sources.createFileID(File ? *File : nullptr, SourceLocation(),
SrcMgr::C_User);
}
@@ -239,6 +290,95 @@ static void outputReplacementsXML(const Replacements &Replaces) {
}
}
+// If BufStr has an invalid BOM, returns the BOM name; otherwise, returns
+// nullptr.
+static const char *getInValidBOM(StringRef BufStr) {
+ // Check to see if the buffer has a UTF Byte Order Mark (BOM).
+ // We only support UTF-8 with and without a BOM right now. See
+ // https://en.wikipedia.org/wiki/Byte_order_mark#Byte_order_marks_by_encoding
+ // for more information.
+ const char *InvalidBOM =
+ llvm::StringSwitch<const char *>(BufStr)
+ .StartsWith(llvm::StringLiteral::withInnerNUL("\x00\x00\xFE\xFF"),
+ "UTF-32 (BE)")
+ .StartsWith(llvm::StringLiteral::withInnerNUL("\xFF\xFE\x00\x00"),
+ "UTF-32 (LE)")
+ .StartsWith("\xFE\xFF", "UTF-16 (BE)")
+ .StartsWith("\xFF\xFE", "UTF-16 (LE)")
+ .StartsWith("\x2B\x2F\x76", "UTF-7")
+ .StartsWith("\xF7\x64\x4C", "UTF-1")
+ .StartsWith("\xDD\x73\x66\x73", "UTF-EBCDIC")
+ .StartsWith("\x0E\xFE\xFF", "SCSU")
+ .StartsWith("\xFB\xEE\x28", "BOCU-1")
+ .StartsWith("\x84\x31\x95\x33", "GB-18030")
+ .Default(nullptr);
+ return InvalidBOM;
+}
+
+static bool
+emitReplacementWarnings(const Replacements &Replaces, StringRef AssumedFileName,
+ const std::unique_ptr<llvm::MemoryBuffer> &Code) {
+ if (Replaces.empty()) {
+ return false;
+ }
+
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ DiagOpts->ShowColors = (ShowColors && !NoShowColors);
+
+ TextDiagnosticPrinter *DiagsBuffer =
+ new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts, false);
+
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, &*DiagOpts, DiagsBuffer));
+
+ IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
+ new llvm::vfs::InMemoryFileSystem);
+ FileManager Files(FileSystemOptions(), InMemoryFileSystem);
+ SourceManager Sources(*Diags, Files);
+ FileID FileID = createInMemoryFile(AssumedFileName, Code.get(), Sources,
+ Files, InMemoryFileSystem.get());
+
+ const unsigned ID = Diags->getCustomDiagID(
+ WarningsAsErrors ? clang::DiagnosticsEngine::Error
+ : clang::DiagnosticsEngine::Warning,
+ "code should be clang-formatted [-Wclang-format-violations]");
+
+ unsigned Errors = 0;
+ DiagsBuffer->BeginSourceFile(LangOptions(), nullptr);
+ if (WarnFormat && !NoWarnFormat) {
+ for (const auto &R : Replaces) {
+ Diags->Report(
+ Sources.getLocForStartOfFile(FileID).getLocWithOffset(R.getOffset()),
+ ID);
+ Errors++;
+ if (ErrorLimit && Errors >= ErrorLimit)
+ break;
+ }
+ }
+ DiagsBuffer->EndSourceFile();
+ return WarningsAsErrors;
+}
+
+static void outputXML(const Replacements &Replaces,
+ const Replacements &FormatChanges,
+ const FormattingAttemptStatus &Status,
+ const cl::opt<unsigned> &Cursor,
+ unsigned CursorPosition) {
+ outs() << "<?xml version='1.0'?>\n<replacements "
+ "xml:space='preserve' incomplete_format='"
+ << (Status.FormatComplete ? "false" : "true") << "'";
+ if (!Status.FormatComplete)
+ outs() << " line='" << Status.Line << "'";
+ outs() << ">\n";
+ if (Cursor.getNumOccurrences() != 0)
+ outs() << "<cursor>" << FormatChanges.getShiftedCodePosition(CursorPosition)
+ << "</cursor>\n";
+
+ outputReplacementsXML(Replaces);
+ outs() << "</replacements>\n";
+}
+
// Returns true on error.
static bool format(StringRef FileName) {
if (!OutputXML && Inplace && FileName == "-") {
@@ -248,8 +388,8 @@ static bool format(StringRef FileName) {
// On Windows, overwriting a file with an open file mapping doesn't work,
// so read the whole file into memory when formatting in-place.
ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
- !OutputXML && Inplace ? MemoryBuffer::getFileAsStream(FileName) :
- MemoryBuffer::getFileOrSTDIN(FileName);
+ !OutputXML && Inplace ? MemoryBuffer::getFileAsStream(FileName)
+ : MemoryBuffer::getFileOrSTDIN(FileName);
if (std::error_code EC = CodeOrErr.getError()) {
errs() << EC.message() << "\n";
return true;
@@ -258,25 +398,9 @@ static bool format(StringRef FileName) {
if (Code->getBufferSize() == 0)
return false; // Empty files are formatted correctly.
- // Check to see if the buffer has a UTF Byte Order Mark (BOM).
- // We only support UTF-8 with and without a BOM right now. See
- // https://en.wikipedia.org/wiki/Byte_order_mark#Byte_order_marks_by_encoding
- // for more information.
StringRef BufStr = Code->getBuffer();
- const char *InvalidBOM = llvm::StringSwitch<const char *>(BufStr)
- .StartsWith(llvm::StringLiteral::withInnerNUL("\x00\x00\xFE\xFF"),
- "UTF-32 (BE)")
- .StartsWith(llvm::StringLiteral::withInnerNUL("\xFF\xFE\x00\x00"),
- "UTF-32 (LE)")
- .StartsWith("\xFE\xFF", "UTF-16 (BE)")
- .StartsWith("\xFF\xFE", "UTF-16 (LE)")
- .StartsWith("\x2B\x2F\x76", "UTF-7")
- .StartsWith("\xF7\x64\x4C", "UTF-1")
- .StartsWith("\xDD\x73\x66\x73", "UTF-EBCDIC")
- .StartsWith("\x0E\xFE\xFF", "SCSU")
- .StartsWith("\xFB\xEE\x28", "BOCU-1")
- .StartsWith("\x84\x31\x95\x33", "GB-18030")
- .Default(nullptr);
+
+ const char *InvalidBOM = getInValidBOM(BufStr);
if (InvalidBOM) {
errs() << "error: encoding with unsupported byte order mark \""
@@ -312,23 +436,15 @@ static bool format(StringRef FileName) {
// Get new affected ranges after sorting `#includes`.
Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges);
FormattingAttemptStatus Status;
- Replacements FormatChanges = reformat(*FormatStyle, *ChangedCode, Ranges,
- AssumedFileName, &Status);
+ Replacements FormatChanges =
+ reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status);
Replaces = Replaces.merge(FormatChanges);
- if (OutputXML) {
- outs() << "<?xml version='1.0'?>\n<replacements "
- "xml:space='preserve' incomplete_format='"
- << (Status.FormatComplete ? "false" : "true") << "'";
- if (!Status.FormatComplete)
- outs() << " line='" << Status.Line << "'";
- outs() << ">\n";
- if (Cursor.getNumOccurrences() != 0)
- outs() << "<cursor>"
- << FormatChanges.getShiftedCodePosition(CursorPosition)
- << "</cursor>\n";
-
- outputReplacementsXML(Replaces);
- outs() << "</replacements>\n";
+ if (OutputXML || DryRun) {
+ if (DryRun) {
+ return emitReplacementWarnings(Replaces, AssumedFileName, Code);
+ } else {
+ outputXML(Replaces, FormatChanges, Status, Cursor, CursorPosition);
+ }
} else {
IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem(
new llvm::vfs::InMemoryFileSystem);
@@ -360,13 +476,45 @@ static bool format(StringRef FileName) {
return false;
}
-} // namespace format
-} // namespace clang
+} // namespace format
+} // namespace clang
static void PrintVersion(raw_ostream &OS) {
OS << clang::getClangToolFullVersion("clang-format") << '\n';
}
+// Dump the configuration.
+static int dumpConfig() {
+ StringRef FileName;
+ std::unique_ptr<llvm::MemoryBuffer> Code;
+ if (FileNames.empty()) {
+ // We can't read the code to detect the language if there's no
+ // file name, so leave Code empty here.
+ FileName = AssumeFileName;
+ } else {
+ // Read in the code in case the filename alone isn't enough to
+ // detect the language.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
+ MemoryBuffer::getFileOrSTDIN(FileNames[0]);
+ if (std::error_code EC = CodeOrErr.getError()) {
+ llvm::errs() << EC.message() << "\n";
+ return 1;
+ }
+ FileName = (FileNames[0] == "-") ? AssumeFileName : FileNames[0];
+ Code = std::move(CodeOrErr.get());
+ }
+ llvm::Expected<clang::format::FormatStyle> FormatStyle =
+ clang::format::getStyle(Style, FileName, FallbackStyle,
+ Code ? Code->getBuffer() : "");
+ if (!FormatStyle) {
+ llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n";
+ return 1;
+ }
+ std::string Config = clang::format::configurationAsText(*FormatStyle);
+ outs() << Config << "\n";
+ return 0;
+}
+
int main(int argc, const char **argv) {
llvm::InitLLVM X(argc, argv);
@@ -388,34 +536,7 @@ int main(int argc, const char **argv) {
}
if (DumpConfig) {
- StringRef FileName;
- std::unique_ptr<llvm::MemoryBuffer> Code;
- if (FileNames.empty()) {
- // We can't read the code to detect the language if there's no
- // file name, so leave Code empty here.
- FileName = AssumeFileName;
- } else {
- // Read in the code in case the filename alone isn't enough to
- // detect the language.
- ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr =
- MemoryBuffer::getFileOrSTDIN(FileNames[0]);
- if (std::error_code EC = CodeOrErr.getError()) {
- llvm::errs() << EC.message() << "\n";
- return 1;
- }
- FileName = (FileNames[0] == "-") ? AssumeFileName : FileNames[0];
- Code = std::move(CodeOrErr.get());
- }
- llvm::Expected<clang::format::FormatStyle> FormatStyle =
- clang::format::getStyle(Style, FileName, FallbackStyle,
- Code ? Code->getBuffer() : "");
- if (!FormatStyle) {
- llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n";
- return 1;
- }
- std::string Config = clang::format::configurationAsText(*FormatStyle);
- outs() << Config << "\n";
- return 0;
+ return dumpConfig();
}
bool Error = false;
@@ -423,7 +544,8 @@ int main(int argc, const char **argv) {
Error = clang::format::format("-");
return Error ? 1 : 0;
}
- if (FileNames.size() != 1 && (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty())) {
+ if (FileNames.size() != 1 &&
+ (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty())) {
errs() << "error: -offset, -length and -lines can only be used for "
"single file.\n";
return 1;
diff --git a/tools/clang-offload-wrapper/CMakeLists.txt b/tools/clang-offload-wrapper/CMakeLists.txt
new file mode 100644
index 000000000000..6f8940f88eab
--- /dev/null
+++ b/tools/clang-offload-wrapper/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(LLVM_LINK_COMPONENTS BitWriter Core Support TransformUtils)
+
+if(NOT CLANG_BUILT_STANDALONE)
+ set(tablegen_deps intrinsics_gen)
+endif()
+
+add_clang_tool(clang-offload-wrapper
+ ClangOffloadWrapper.cpp
+
+ DEPENDS
+ ${tablegen_deps}
+ )
+
+set(CLANG_OFFLOAD_WRAPPER_LIB_DEPS
+ clangBasic
+ )
+
+add_dependencies(clang clang-offload-wrapper)
+
+clang_target_link_libraries(clang-offload-wrapper
+ PRIVATE
+ ${CLANG_OFFLOAD_WRAPPER_LIB_DEPS}
+ )
diff --git a/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp b/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp
new file mode 100644
index 000000000000..c3863422adf6
--- /dev/null
+++ b/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp
@@ -0,0 +1,371 @@
+//===-- clang-offload-wrapper/ClangOffloadWrapper.cpp -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of the offload wrapper tool. It takes offload target binaries
+/// as input and creates wrapper bitcode file containing target binaries
+/// packaged as data. Wrapper bitcode also includes initialization code which
+/// registers target binaries in offloading runtime at program startup.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Version.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Bitcode/BitcodeWriter.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+
+static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
+
+// Mark all our options with this category, everything else (except for -version
+// and -help) will be hidden.
+static cl::OptionCategory
+ ClangOffloadWrapperCategory("clang-offload-wrapper options");
+
+static cl::opt<std::string> Output("o", cl::Required,
+ cl::desc("Output filename"),
+ cl::value_desc("filename"),
+ cl::cat(ClangOffloadWrapperCategory));
+
+static cl::list<std::string> Inputs(cl::Positional, cl::OneOrMore,
+ cl::desc("<input files>"),
+ cl::cat(ClangOffloadWrapperCategory));
+
+static cl::opt<std::string>
+ Target("target", cl::Required,
+ cl::desc("Target triple for the output module"),
+ cl::value_desc("triple"), cl::cat(ClangOffloadWrapperCategory));
+
+namespace {
+
+class BinaryWrapper {
+ LLVMContext C;
+ Module M;
+
+ StructType *EntryTy = nullptr;
+ StructType *ImageTy = nullptr;
+ StructType *DescTy = nullptr;
+
+private:
+ IntegerType *getSizeTTy() {
+ switch (M.getDataLayout().getPointerTypeSize(Type::getInt8PtrTy(C))) {
+ case 4u:
+ return Type::getInt32Ty(C);
+ case 8u:
+ return Type::getInt64Ty(C);
+ }
+ llvm_unreachable("unsupported pointer type size");
+ }
+
+ // struct __tgt_offload_entry {
+ // void *addr;
+ // char *name;
+ // size_t size;
+ // int32_t flags;
+ // int32_t reserved;
+ // };
+ StructType *getEntryTy() {
+ if (!EntryTy)
+ EntryTy = StructType::create("__tgt_offload_entry", Type::getInt8PtrTy(C),
+ Type::getInt8PtrTy(C), getSizeTTy(),
+ Type::getInt32Ty(C), Type::getInt32Ty(C));
+ return EntryTy;
+ }
+
+ PointerType *getEntryPtrTy() { return PointerType::getUnqual(getEntryTy()); }
+
+ // struct __tgt_device_image {
+ // void *ImageStart;
+ // void *ImageEnd;
+ // __tgt_offload_entry *EntriesBegin;
+ // __tgt_offload_entry *EntriesEnd;
+ // };
+ StructType *getDeviceImageTy() {
+ if (!ImageTy)
+ ImageTy = StructType::create("__tgt_device_image", Type::getInt8PtrTy(C),
+ Type::getInt8PtrTy(C), getEntryPtrTy(),
+ getEntryPtrTy());
+ return ImageTy;
+ }
+
+ PointerType *getDeviceImagePtrTy() {
+ return PointerType::getUnqual(getDeviceImageTy());
+ }
+
+ // struct __tgt_bin_desc {
+ // int32_t NumDeviceImages;
+ // __tgt_device_image *DeviceImages;
+ // __tgt_offload_entry *HostEntriesBegin;
+ // __tgt_offload_entry *HostEntriesEnd;
+ // };
+ StructType *getBinDescTy() {
+ if (!DescTy)
+ DescTy = StructType::create("__tgt_bin_desc", Type::getInt32Ty(C),
+ getDeviceImagePtrTy(), getEntryPtrTy(),
+ getEntryPtrTy());
+ return DescTy;
+ }
+
+ PointerType *getBinDescPtrTy() {
+ return PointerType::getUnqual(getBinDescTy());
+ }
+
+ /// Creates binary descriptor for the given device images. Binary descriptor
+ /// is an object that is passed to the offloading runtime at program startup
+ /// and it describes all device images available in the executable or shared
+ /// library. It is defined as follows
+ ///
+ /// __attribute__((visibility("hidden")))
+ /// extern __tgt_offload_entry *__start_omp_offloading_entries;
+ /// __attribute__((visibility("hidden")))
+ /// extern __tgt_offload_entry *__stop_omp_offloading_entries;
+ ///
+ /// static const char Image0[] = { <Bufs.front() contents> };
+ /// ...
+ /// static const char ImageN[] = { <Bufs.back() contents> };
+ ///
+ /// static const __tgt_device_image Images[] = {
+ /// {
+ /// Image0, /*ImageStart*/
+ /// Image0 + sizeof(Image0), /*ImageEnd*/
+ /// __start_omp_offloading_entries, /*EntriesBegin*/
+ /// __stop_omp_offloading_entries /*EntriesEnd*/
+ /// },
+ /// ...
+ /// {
+ /// ImageN, /*ImageStart*/
+ /// ImageN + sizeof(ImageN), /*ImageEnd*/
+ /// __start_omp_offloading_entries, /*EntriesBegin*/
+ /// __stop_omp_offloading_entries /*EntriesEnd*/
+ /// }
+ /// };
+ ///
+ /// static const __tgt_bin_desc BinDesc = {
+ /// sizeof(Images) / sizeof(Images[0]), /*NumDeviceImages*/
+ /// Images, /*DeviceImages*/
+ /// __start_omp_offloading_entries, /*HostEntriesBegin*/
+ /// __stop_omp_offloading_entries /*HostEntriesEnd*/
+ /// };
+ ///
+ /// Global variable that represents BinDesc is returned.
+ GlobalVariable *createBinDesc(ArrayRef<ArrayRef<char>> Bufs) {
+ // Create external begin/end symbols for the offload entries table.
+ auto *EntriesB = new GlobalVariable(
+ M, getEntryTy(), /*isConstant*/ true, GlobalValue::ExternalLinkage,
+ /*Initializer*/ nullptr, "__start_omp_offloading_entries");
+ EntriesB->setVisibility(GlobalValue::HiddenVisibility);
+ auto *EntriesE = new GlobalVariable(
+ M, getEntryTy(), /*isConstant*/ true, GlobalValue::ExternalLinkage,
+ /*Initializer*/ nullptr, "__stop_omp_offloading_entries");
+ EntriesE->setVisibility(GlobalValue::HiddenVisibility);
+
+ // We assume that external begin/end symbols that we have created above will
+ // be defined by the linker. But linker will do that only if linker inputs
+ // have section with "omp_offloading_entries" name which is not guaranteed.
+ // So, we just create dummy zero sized object in the offload entries section
+ // to force linker to define those symbols.
+ auto *DummyInit =
+ ConstantAggregateZero::get(ArrayType::get(getEntryTy(), 0u));
+ auto *DummyEntry = new GlobalVariable(
+ M, DummyInit->getType(), true, GlobalVariable::ExternalLinkage,
+ DummyInit, "__dummy.omp_offloading.entry");
+ DummyEntry->setSection("omp_offloading_entries");
+ DummyEntry->setVisibility(GlobalValue::HiddenVisibility);
+
+ auto *Zero = ConstantInt::get(getSizeTTy(), 0u);
+ Constant *ZeroZero[] = {Zero, Zero};
+
+ // Create initializer for the images array.
+ SmallVector<Constant *, 4u> ImagesInits;
+ ImagesInits.reserve(Bufs.size());
+ for (ArrayRef<char> Buf : Bufs) {
+ auto *Data = ConstantDataArray::get(C, Buf);
+ auto *Image = new GlobalVariable(M, Data->getType(), /*isConstant*/ true,
+ GlobalVariable::InternalLinkage, Data,
+ ".omp_offloading.device_image");
+ Image->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
+
+ auto *Size = ConstantInt::get(getSizeTTy(), Buf.size());
+ Constant *ZeroSize[] = {Zero, Size};
+
+ auto *ImageB = ConstantExpr::getGetElementPtr(Image->getValueType(),
+ Image, ZeroZero);
+ auto *ImageE = ConstantExpr::getGetElementPtr(Image->getValueType(),
+ Image, ZeroSize);
+
+ ImagesInits.push_back(ConstantStruct::get(getDeviceImageTy(), ImageB,
+ ImageE, EntriesB, EntriesE));
+ }
+
+ // Then create images array.
+ auto *ImagesData = ConstantArray::get(
+ ArrayType::get(getDeviceImageTy(), ImagesInits.size()), ImagesInits);
+
+ auto *Images =
+ new GlobalVariable(M, ImagesData->getType(), /*isConstant*/ true,
+ GlobalValue::InternalLinkage, ImagesData,
+ ".omp_offloading.device_images");
+ Images->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
+
+ auto *ImagesB = ConstantExpr::getGetElementPtr(Images->getValueType(),
+ Images, ZeroZero);
+
+ // And finally create the binary descriptor object.
+ auto *DescInit = ConstantStruct::get(
+ getBinDescTy(),
+ ConstantInt::get(Type::getInt32Ty(C), ImagesInits.size()), ImagesB,
+ EntriesB, EntriesE);
+
+ return new GlobalVariable(M, DescInit->getType(), /*isConstant*/ true,
+ GlobalValue::InternalLinkage, DescInit,
+ ".omp_offloading.descriptor");
+ }
+
+ void createRegisterFunction(GlobalVariable *BinDesc) {
+ auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
+ auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage,
+ ".omp_offloading.descriptor_reg", &M);
+ Func->setSection(".text.startup");
+
+ // Get __tgt_register_lib function declaration.
+ auto *RegFuncTy = FunctionType::get(Type::getVoidTy(C), getBinDescPtrTy(),
+ /*isVarArg*/ false);
+ FunctionCallee RegFuncC =
+ M.getOrInsertFunction("__tgt_register_lib", RegFuncTy);
+
+ // Construct function body
+ IRBuilder<> Builder(BasicBlock::Create(C, "entry", Func));
+ Builder.CreateCall(RegFuncC, BinDesc);
+ Builder.CreateRetVoid();
+
+ // Add this function to constructors.
+ appendToGlobalCtors(M, Func, 0);
+ }
+
+ void createUnregisterFunction(GlobalVariable *BinDesc) {
+ auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
+ auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage,
+ ".omp_offloading.descriptor_unreg", &M);
+ Func->setSection(".text.startup");
+
+ // Get __tgt_unregister_lib function declaration.
+ auto *UnRegFuncTy = FunctionType::get(Type::getVoidTy(C), getBinDescPtrTy(),
+ /*isVarArg*/ false);
+ FunctionCallee UnRegFuncC =
+ M.getOrInsertFunction("__tgt_unregister_lib", UnRegFuncTy);
+
+ // Construct function body
+ IRBuilder<> Builder(BasicBlock::Create(C, "entry", Func));
+ Builder.CreateCall(UnRegFuncC, BinDesc);
+ Builder.CreateRetVoid();
+
+ // Add this function to global destructors.
+ appendToGlobalDtors(M, Func, 0);
+ }
+
+public:
+ BinaryWrapper(StringRef Target) : M("offload.wrapper.object", C) {
+ M.setTargetTriple(Target);
+ }
+
+ const Module &wrapBinaries(ArrayRef<ArrayRef<char>> Binaries) {
+ GlobalVariable *Desc = createBinDesc(Binaries);
+ assert(Desc && "no binary descriptor");
+ createRegisterFunction(Desc);
+ createUnregisterFunction(Desc);
+ return M;
+ }
+};
+
+} // anonymous namespace
+
+int main(int argc, const char **argv) {
+ sys::PrintStackTraceOnErrorSignal(argv[0]);
+
+ cl::HideUnrelatedOptions(ClangOffloadWrapperCategory);
+ cl::SetVersionPrinter([](raw_ostream &OS) {
+ OS << clang::getClangToolFullVersion("clang-offload-wrapper") << '\n';
+ });
+ cl::ParseCommandLineOptions(
+ argc, argv,
+ "A tool to create a wrapper bitcode for offload target binaries. Takes "
+ "offload\ntarget binaries as input and produces bitcode file containing "
+ "target binaries packaged\nas data and initialization code which "
+ "registers target binaries in offload runtime.\n");
+
+ if (Help) {
+ cl::PrintHelpMessage();
+ return 0;
+ }
+
+ auto reportError = [argv](Error E) {
+ logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0]));
+ };
+
+ if (Triple(Target).getArch() == Triple::UnknownArch) {
+ reportError(createStringError(
+ errc::invalid_argument, "'" + Target + "': unsupported target triple"));
+ return 1;
+ }
+
+ // Read device binaries.
+ SmallVector<std::unique_ptr<MemoryBuffer>, 4u> Buffers;
+ SmallVector<ArrayRef<char>, 4u> Images;
+ Buffers.reserve(Inputs.size());
+ Images.reserve(Inputs.size());
+ for (const std::string &File : Inputs) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+ MemoryBuffer::getFileOrSTDIN(File);
+ if (!BufOrErr) {
+ reportError(createFileError(File, BufOrErr.getError()));
+ return 1;
+ }
+ const std::unique_ptr<MemoryBuffer> &Buf =
+ Buffers.emplace_back(std::move(*BufOrErr));
+ Images.emplace_back(Buf->getBufferStart(), Buf->getBufferSize());
+ }
+
+ // Create the output file to write the resulting bitcode to.
+ std::error_code EC;
+ ToolOutputFile Out(Output, EC, sys::fs::OF_None);
+ if (EC) {
+ reportError(createFileError(Output, EC));
+ return 1;
+ }
+
+ // Create a wrapper for device binaries and write its bitcode to the file.
+ WriteBitcodeToFile(BinaryWrapper(Target).wrapBinaries(
+ makeArrayRef(Images.data(), Images.size())),
+ Out.os());
+ if (Out.os().has_error()) {
+ reportError(createFileError(Output, Out.os().error()));
+ return 1;
+ }
+
+ // Success.
+ Out.keep();
+ return 0;
+}
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index 7315a1357089..9e4f32da884f 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -194,8 +194,8 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// Register the support for object-file-wrapped Clang modules.
auto PCHOps = Clang->getPCHContainerOperations();
- PCHOps->registerWriter(llvm::make_unique<ObjectFilePCHContainerWriter>());
- PCHOps->registerReader(llvm::make_unique<ObjectFilePCHContainerReader>());
+ PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
+ PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
// Initialize targets first, so that --version shows registered targets.
llvm::InitializeAllTargets();
@@ -213,12 +213,13 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
- bool Success = CompilerInvocation::CreateFromArgs(
- Clang->getInvocation(), Argv.begin(), Argv.end(), Diags);
-
- if (Clang->getFrontendOpts().TimeTrace)
- llvm::timeTraceProfilerInitialize();
+ bool Success =
+ CompilerInvocation::CreateFromArgs(Clang->getInvocation(), Argv, Diags);
+ if (Clang->getFrontendOpts().TimeTrace) {
+ llvm::timeTraceProfilerInitialize(
+ Clang->getFrontendOpts().TimeTraceGranularity);
+ }
// --print-supported-cpus takes priority over the actual compilation.
if (Clang->getFrontendOpts().PrintSupportedCPUs)
return PrintSupportedCPUs(Clang->getTargetOpts().Triple);
@@ -252,26 +253,23 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// If any timers were active but haven't been destroyed yet, print their
// results now. This happens in -disable-free mode.
llvm::TimerGroup::printAll(llvm::errs());
+ llvm::TimerGroup::clearAll();
if (llvm::timeTraceProfilerEnabled()) {
SmallString<128> Path(Clang->getFrontendOpts().OutputFile);
llvm::sys::path::replace_extension(Path, "json");
- auto profilerOutput =
- Clang->createOutputFile(Path.str(),
- /*Binary=*/false,
- /*RemoveFileOnSignal=*/false, "",
- /*Extension=*/"json",
- /*useTemporary=*/false);
-
- llvm::timeTraceProfilerWrite(*profilerOutput);
- // FIXME(ibiryukov): make profilerOutput flush in destructor instead.
- profilerOutput->flush();
- llvm::timeTraceProfilerCleanup();
-
- llvm::errs() << "Time trace json-file dumped to " << Path.str() << "\n";
- llvm::errs()
- << "Use chrome://tracing or Speedscope App "
- "(https://www.speedscope.app) for flamegraph visualization\n";
+ if (auto profilerOutput =
+ Clang->createOutputFile(Path.str(),
+ /*Binary=*/false,
+ /*RemoveFileOnSignal=*/false, "",
+ /*Extension=*/"json",
+ /*useTemporary=*/false)) {
+
+ llvm::timeTraceProfilerWrite(*profilerOutput);
+ // FIXME(ibiryukov): make profilerOutput flush in destructor instead.
+ profilerOutput->flush();
+ llvm::timeTraceProfilerCleanup();
+ }
}
// Our error handler depends on the Diagnostics object, which we're
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index a2902b6aa926..ae58a95f36f5 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -131,6 +131,7 @@ struct AssemblerInvocation {
unsigned RelaxAll : 1;
unsigned NoExecStack : 1;
unsigned FatalWarnings : 1;
+ unsigned NoWarn : 1;
unsigned IncrementalLinkerCompatible : 1;
unsigned EmbedBitcode : 1;
@@ -156,6 +157,7 @@ public:
RelaxAll = 0;
NoExecStack = 0;
FatalWarnings = 0;
+ NoWarn = 0;
IncrementalLinkerCompatible = 0;
DwarfVersion = 0;
EmbedBitcode = 0;
@@ -174,12 +176,12 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
bool Success = true;
// Parse the arguments.
- std::unique_ptr<OptTable> OptTbl(createDriverOptTable());
+ const OptTable &OptTbl = getDriverOptTable();
const unsigned IncludedFlagsBitmask = options::CC1AsOption;
unsigned MissingArgIndex, MissingArgCount;
- InputArgList Args = OptTbl->ParseArgs(Argv, MissingArgIndex, MissingArgCount,
- IncludedFlagsBitmask);
+ InputArgList Args = OptTbl.ParseArgs(Argv, MissingArgIndex, MissingArgCount,
+ IncludedFlagsBitmask);
// Check for missing argument error.
if (MissingArgCount) {
@@ -192,7 +194,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
auto ArgString = A->getAsString(Args);
std::string Nearest;
- if (OptTbl->findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
+ if (OptTbl.findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
Diags.Report(diag::err_drv_unknown_argument) << ArgString;
else
Diags.Report(diag::err_drv_unknown_argument_with_suggestion)
@@ -285,6 +287,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
+ Opts.NoWarn = Args.hasArg(OPT_massembler_no_warn);
Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
Opts.TargetABI = Args.getLastArgValue(OPT_target_abi);
Opts.IncrementalLinkerCompatible =
@@ -312,8 +315,8 @@ getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
sys::RemoveFileOnSignal(Path);
std::error_code EC;
- auto Out = llvm::make_unique<raw_fd_ostream>(
- Path, EC, (Binary ? sys::fs::F_None : sys::fs::F_Text));
+ auto Out = std::make_unique<raw_fd_ostream>(
+ Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_Text));
if (EC) {
Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
return nullptr;
@@ -374,7 +377,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
- MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr);
+ MCTargetOptions MCOptions;
+ MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr, &MCOptions);
bool PIC = false;
if (Opts.RelocationModel == "static") {
@@ -431,7 +435,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
raw_pwrite_stream *Out = FDOS.get();
std::unique_ptr<buffer_ostream> BOS;
- MCTargetOptions MCOptions;
+ MCOptions.MCNoWarn = Opts.NoWarn;
+ MCOptions.MCFatalWarnings = Opts.FatalWarnings;
MCOptions.ABIName = Opts.TargetABI;
// FIXME: There is a bit of code duplication with addPassesToEmitFile.
@@ -445,7 +450,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
std::unique_ptr<MCAsmBackend> MAB(
TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
- auto FOut = llvm::make_unique<formatted_raw_ostream>(*Out);
+ auto FOut = std::make_unique<formatted_raw_ostream>(*Out);
Str.reset(TheTarget->createAsmStreamer(
Ctx, std::move(FOut), /*asmverbose*/ true,
/*useDwarfDirectory*/ true, IP, std::move(CE), std::move(MAB),
@@ -456,7 +461,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
"Invalid file type!");
if (!FDOS->supportsSeeking()) {
- BOS = make_unique<buffer_ostream>(*FDOS);
+ BOS = std::make_unique<buffer_ostream>(*FDOS);
Out = BOS.get();
}
@@ -569,11 +574,11 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
return 1;
if (Asm.ShowHelp) {
- std::unique_ptr<OptTable> Opts(driver::createDriverOptTable());
- Opts->PrintHelp(llvm::outs(), "clang -cc1as [options] file...",
- "Clang Integrated Assembler",
- /*Include=*/driver::options::CC1AsOption, /*Exclude=*/0,
- /*ShowAllAliases=*/false);
+ getDriverOptTable().PrintHelp(
+ llvm::outs(), "clang -cc1as [options] file...",
+ "Clang Integrated Assembler",
+ /*Include=*/driver::options::CC1AsOption, /*Exclude=*/0,
+ /*ShowAllAliases=*/false);
return 0;
}
@@ -590,7 +595,7 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// FIXME: Remove this, one day.
if (!Asm.LLVMArgs.empty()) {
unsigned NumArgs = Asm.LLVMArgs.size();
- auto Args = llvm::make_unique<const char*[]>(NumArgs + 2);
+ auto Args = std::make_unique<const char*[]>(NumArgs + 2);
Args[0] = "clang (LLVM option parsing)";
for (unsigned i = 0; i != NumArgs; ++i)
Args[i + 1] = Asm.LLVMArgs[i].c_str();
@@ -604,6 +609,7 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// If any timers were active but haven't been destroyed yet, print their
// results now.
TimerGroup::printAll(errs());
+ TimerGroup::clearAll();
return !!Failed;
}
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index dfc96d308ab5..f1600490017d 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -13,6 +13,7 @@
#include "clang/Driver/Driver.h"
#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/Stack.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
@@ -270,10 +271,9 @@ static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
static DiagnosticOptions *
CreateAndPopulateDiagOpts(ArrayRef<const char *> argv) {
auto *DiagOpts = new DiagnosticOptions;
- std::unique_ptr<OptTable> Opts(createDriverOptTable());
unsigned MissingArgIndex, MissingArgCount;
- InputArgList Args =
- Opts->ParseArgs(argv.slice(1), MissingArgIndex, MissingArgCount);
+ InputArgList Args = getDriverOptTable().ParseArgs(
+ argv.slice(1), 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.
@@ -319,6 +319,7 @@ static int ExecuteCC1Tool(ArrayRef<const char *> argv, StringRef Tool) {
}
int main(int argc_, const char **argv_) {
+ noteBottomOfStack();
llvm::InitLLVM X(argc_, argv_);
SmallVector<const char *, 256> argv(argv_, argv_ + argc_);
@@ -498,6 +499,7 @@ int main(int argc_, const char **argv_) {
// If any timers were active but haven't been destroyed yet, print their
// results now. This happens in -disable-free mode.
llvm::TimerGroup::printAll(llvm::errs());
+ llvm::TimerGroup::clearAll();
#ifdef _WIN32
// Exit status should not be negative on Win32, unless abnormal termination.
diff --git a/utils/TableGen/ClangASTNodesEmitter.cpp b/utils/TableGen/ClangASTNodesEmitter.cpp
index a0bbdbab3354..3ece9be6a5c7 100644
--- a/utils/TableGen/ClangASTNodesEmitter.cpp
+++ b/utils/TableGen/ClangASTNodesEmitter.cpp
@@ -10,6 +10,8 @@
//
//===----------------------------------------------------------------------===//
+#include "TableGenBackends.h"
+
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <cctype>
@@ -173,15 +175,14 @@ void ClangASTNodesEmitter::run(raw_ostream &OS) {
OS << "#undef ABSTRACT_" << macroName(Root.getName()) << "\n";
}
-namespace clang {
-void EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS,
- const std::string &N, const std::string &S) {
+void clang::EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS,
+ const std::string &N, const std::string &S) {
ClangASTNodesEmitter(RK, N, S).run(OS);
}
// Emits and addendum to a .inc file to enumerate the clang declaration
// contexts.
-void EmitClangDeclContext(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitClangDeclContext(RecordKeeper &Records, raw_ostream &OS) {
// FIXME: Find a .td file format to allow for this to be represented better.
emitSourceFileHeader("List of AST Decl nodes", OS);
@@ -225,4 +226,3 @@ void EmitClangDeclContext(RecordKeeper &Records, raw_ostream &OS) {
OS << "#undef DECL_CONTEXT\n";
OS << "#undef DECL_CONTEXT_BASE\n";
}
-} // end namespace clang
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index f315262ad0f4..0d92a321c747 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -10,6 +10,8 @@
//
//===----------------------------------------------------------------------===//
+#include "TableGenBackends.h"
+
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
@@ -303,6 +305,8 @@ namespace {
std::string getIsOmitted() const override {
if (type == "IdentifierInfo *")
return "!get" + getUpperName().str() + "()";
+ if (type == "TypeSourceInfo *")
+ return "!get" + getUpperName().str() + "Loc()";
if (type == "ParamIdx")
return "!get" + getUpperName().str() + "().isValid()";
return "false";
@@ -336,6 +340,8 @@ namespace {
<< " OS << \" \" << SA->get" << getUpperName()
<< "()->getName();\n";
} else if (type == "TypeSourceInfo *") {
+ if (isOptional())
+ OS << " if (SA->get" << getUpperName() << "Loc())";
OS << " OS << \" \" << SA->get" << getUpperName()
<< "().getAsString();\n";
} else if (type == "bool") {
@@ -1251,51 +1257,51 @@ createArgument(const Record &Arg, StringRef Attr,
llvm::StringRef ArgName = Search->getName();
if (ArgName == "AlignedArgument")
- Ptr = llvm::make_unique<AlignedArgument>(Arg, Attr);
+ Ptr = std::make_unique<AlignedArgument>(Arg, Attr);
else if (ArgName == "EnumArgument")
- Ptr = llvm::make_unique<EnumArgument>(Arg, Attr);
+ Ptr = std::make_unique<EnumArgument>(Arg, Attr);
else if (ArgName == "ExprArgument")
- Ptr = llvm::make_unique<ExprArgument>(Arg, Attr);
+ Ptr = std::make_unique<ExprArgument>(Arg, Attr);
else if (ArgName == "FunctionArgument")
- Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "FunctionDecl *");
+ Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "FunctionDecl *");
else if (ArgName == "NamedArgument")
- Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "NamedDecl *");
+ Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "NamedDecl *");
else if (ArgName == "IdentifierArgument")
- Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "IdentifierInfo *");
+ Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "IdentifierInfo *");
else if (ArgName == "DefaultBoolArgument")
- Ptr = llvm::make_unique<DefaultSimpleArgument>(
+ Ptr = std::make_unique<DefaultSimpleArgument>(
Arg, Attr, "bool", Arg.getValueAsBit("Default"));
else if (ArgName == "BoolArgument")
- Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "bool");
+ Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "bool");
else if (ArgName == "DefaultIntArgument")
- Ptr = llvm::make_unique<DefaultSimpleArgument>(
+ Ptr = std::make_unique<DefaultSimpleArgument>(
Arg, Attr, "int", Arg.getValueAsInt("Default"));
else if (ArgName == "IntArgument")
- Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "int");
+ Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "int");
else if (ArgName == "StringArgument")
- Ptr = llvm::make_unique<StringArgument>(Arg, Attr);
+ Ptr = std::make_unique<StringArgument>(Arg, Attr);
else if (ArgName == "TypeArgument")
- Ptr = llvm::make_unique<TypeArgument>(Arg, Attr);
+ Ptr = std::make_unique<TypeArgument>(Arg, Attr);
else if (ArgName == "UnsignedArgument")
- Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "unsigned");
+ Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "unsigned");
else if (ArgName == "VariadicUnsignedArgument")
- Ptr = llvm::make_unique<VariadicArgument>(Arg, Attr, "unsigned");
+ Ptr = std::make_unique<VariadicArgument>(Arg, Attr, "unsigned");
else if (ArgName == "VariadicStringArgument")
- Ptr = llvm::make_unique<VariadicStringArgument>(Arg, Attr);
+ Ptr = std::make_unique<VariadicStringArgument>(Arg, Attr);
else if (ArgName == "VariadicEnumArgument")
- Ptr = llvm::make_unique<VariadicEnumArgument>(Arg, Attr);
+ Ptr = std::make_unique<VariadicEnumArgument>(Arg, Attr);
else if (ArgName == "VariadicExprArgument")
- Ptr = llvm::make_unique<VariadicExprArgument>(Arg, Attr);
+ Ptr = std::make_unique<VariadicExprArgument>(Arg, Attr);
else if (ArgName == "VariadicParamIdxArgument")
- Ptr = llvm::make_unique<VariadicParamIdxArgument>(Arg, Attr);
+ Ptr = std::make_unique<VariadicParamIdxArgument>(Arg, Attr);
else if (ArgName == "VariadicParamOrParamIdxArgument")
- Ptr = llvm::make_unique<VariadicParamOrParamIdxArgument>(Arg, Attr);
+ Ptr = std::make_unique<VariadicParamOrParamIdxArgument>(Arg, Attr);
else if (ArgName == "ParamIdxArgument")
- Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "ParamIdx");
+ Ptr = std::make_unique<SimpleArgument>(Arg, Attr, "ParamIdx");
else if (ArgName == "VariadicIdentifierArgument")
- Ptr = llvm::make_unique<VariadicIdentifierArgument>(Arg, Attr);
+ Ptr = std::make_unique<VariadicIdentifierArgument>(Arg, Attr);
else if (ArgName == "VersionArgument")
- Ptr = llvm::make_unique<VersionArgument>(Arg, Attr);
+ Ptr = std::make_unique<VersionArgument>(Arg, Attr);
if (!Ptr) {
// Search in reverse order so that the most-derived type is handled first.
@@ -1343,7 +1349,7 @@ static void writeGetSpellingFunction(Record &R, raw_ostream &OS) {
return;
}
- OS << " switch (SpellingListIndex) {\n"
+ OS << " switch (getAttributeSpellingListIndex()) {\n"
" default:\n"
" llvm_unreachable(\"Unknown attribute spelling!\");\n"
" return \"(No spelling)\";\n";
@@ -1371,11 +1377,10 @@ writePrettyPrintFunction(Record &R,
return;
}
- OS <<
- " switch (SpellingListIndex) {\n"
- " default:\n"
- " llvm_unreachable(\"Unknown attribute spelling!\");\n"
- " break;\n";
+ OS << " switch (getAttributeSpellingListIndex()) {\n"
+ " default:\n"
+ " llvm_unreachable(\"Unknown attribute spelling!\");\n"
+ " break;\n";
for (unsigned I = 0; I < Spellings.size(); ++ I) {
llvm::SmallString<16> Prefix;
@@ -1556,11 +1561,12 @@ static void writeAttrAccessorDefinition(const Record &R, raw_ostream &OS) {
const StringRef Name = Accessor->getValueAsString("Name");
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Accessor);
- OS << " bool " << Name << "() const { return SpellingListIndex == ";
+ OS << " bool " << Name
+ << "() const { return getAttributeSpellingListIndex() == ";
for (unsigned Index = 0; Index < Spellings.size(); ++Index) {
OS << getSpellingListIndex(SpellingList, Spellings[Index]);
if (Index != Spellings.size() - 1)
- OS << " ||\n SpellingListIndex == ";
+ OS << " ||\n getAttributeSpellingListIndex() == ";
else
OS << "; }\n";
}
@@ -1592,6 +1598,13 @@ CreateSemanticSpellings(const std::vector<FlattenedSpelling> &Spellings,
std::string Ret(" enum Spelling {\n");
std::set<std::string> Uniques;
unsigned Idx = 0;
+
+ // If we have a need to have this many spellings we likely need to add an
+ // extra bit to the SpellingIndex in AttributeCommonInfo, then increase the
+ // value of SpellingNotCalculated there and here.
+ assert(Spellings.size() < 15 &&
+ "Too many spellings, would step on SpellingNotCalculated in "
+ "AttributeCommonInfo");
for (auto I = Spellings.begin(), E = Spellings.end(); I != E; ++I, ++Idx) {
const FlattenedSpelling &S = *I;
const std::string &Variety = S.variety();
@@ -1625,6 +1638,7 @@ CreateSemanticSpellings(const std::vector<FlattenedSpelling> &Spellings,
// enumerator.
Ret += " " + EnumName + " = " + llvm::utostr(Idx);
}
+ Ret += ",\n SpellingNotCalculated = 15\n";
Ret += "\n };\n\n";
return Ret;
}
@@ -2207,16 +2221,15 @@ static void emitClangAttrThisIsaIdentifierArgList(RecordKeeper &Records,
OS << "#endif // CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST\n\n";
}
-namespace clang {
-
// Emits the class definitions for attributes.
-void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("Attribute classes' definitions", OS);
OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n";
OS << "#define LLVM_CLANG_ATTR_CLASSES_INC\n\n";
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+ ParsedAttrMap AttrMap = getParsedAttrList(Records);
for (const auto *Attr : Attrs) {
const Record &R = *Attr;
@@ -2285,38 +2298,97 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
if (!ElideSpelling)
OS << CreateSemanticSpellings(Spellings, SemanticToSyntacticMap);
+ const auto &ParsedAttrSpellingItr = llvm::find_if(
+ AttrMap, [R](const std::pair<std::string, const Record *> &P) {
+ return &R == P.second;
+ });
+
// Emit CreateImplicit factory methods.
- auto emitCreateImplicit = [&](bool emitFake) {
- OS << " static " << R.getName() << "Attr *CreateImplicit(";
+ auto emitCreate = [&](bool Implicit, bool emitFake) {
+ OS << " static " << R.getName() << "Attr *Create";
+ if (Implicit)
+ OS << "Implicit";
+ OS << "(";
OS << "ASTContext &Ctx";
- if (!ElideSpelling)
- OS << ", Spelling S";
for (auto const &ai : Args) {
if (ai->isFake() && !emitFake) continue;
OS << ", ";
ai->writeCtorParameters(OS);
}
- OS << ", SourceRange Loc = SourceRange()";
- OS << ") {\n";
+ OS << ", const AttributeCommonInfo &CommonInfo = {SourceRange{}}) {\n";
OS << " auto *A = new (Ctx) " << R.getName();
- OS << "Attr(Loc, Ctx, ";
+ OS << "Attr(Ctx, CommonInfo";
for (auto const &ai : Args) {
if (ai->isFake() && !emitFake) continue;
- ai->writeImplicitCtorArgs(OS);
OS << ", ";
+ ai->writeImplicitCtorArgs(OS);
+ }
+ OS << ");\n";
+ if (Implicit) {
+ OS << " A->setImplicit(true);\n";
+ }
+ if (Implicit || ElideSpelling) {
+ OS << " if (!A->isAttributeSpellingListCalculated() && "
+ "!A->getAttrName())\n";
+ OS << " A->setAttributeSpellingListIndex(0);\n";
}
- OS << (ElideSpelling ? "0" : "S") << ");\n";
- OS << " A->setImplicit(true);\n";
OS << " return A;\n }\n\n";
};
+ auto emitCreateNoCI = [&](bool Implicit, bool emitFake) {
+ OS <<" static " << R.getName() << "Attr *Create";
+ if (Implicit)
+ OS << "Implicit";
+ OS << "(";
+ OS << "ASTContext &Ctx";
+ for (auto const &ai : Args) {
+ if (ai->isFake() && !emitFake) continue;
+ OS << ", ";
+ ai->writeCtorParameters(OS);
+ }
+ OS << ", SourceRange Range, AttributeCommonInfo::Syntax Syntax";
+ if (!ElideSpelling)
+ OS << ", " << R.getName()
+ << "Attr::Spelling S = "
+ "static_cast<Spelling>(SpellingNotCalculated)";
+ OS << ") {\n";
+ OS << " AttributeCommonInfo I(Range, ";
+
+ if (ParsedAttrSpellingItr != std::end(AttrMap))
+ OS << "AT_" << ParsedAttrSpellingItr->first;
+ else
+ OS << "NoSemaHandlerAttribute";
+
+ OS << ", Syntax";
+ if (!ElideSpelling)
+ OS << ", S";
+ OS << ");\n";
+ OS << " return Create";
+ if (Implicit)
+ OS << "Implicit";
+ OS << "(Ctx";
+ for (auto const &ai : Args) {
+ if (ai->isFake() && !emitFake) continue;
+ OS << ", ";
+ ai->writeImplicitCtorArgs(OS);
+ }
+ OS << ", I);\n";
+ OS << " }\n";
+ };
+
+ auto emitCreates = [&](bool emitFake) {
+ emitCreate(true, emitFake);
+ emitCreate(false, emitFake);
+ emitCreateNoCI(true, emitFake);
+ emitCreateNoCI(false, emitFake);
+ };
+
// Emit a CreateImplicit that takes all the arguments.
- emitCreateImplicit(true);
+ emitCreates(true);
// Emit a CreateImplicit that takes all the non-fake arguments.
- if (HasFakeArg) {
- emitCreateImplicit(false);
- }
+ if (HasFakeArg)
+ emitCreates(false);
// Emit constructors.
auto emitCtor = [&](bool emitOpt, bool emitFake) {
@@ -2325,8 +2397,9 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
if (arg->isOptional()) return emitOpt;
return true;
};
-
- OS << " " << R.getName() << "Attr(SourceRange R, ASTContext &Ctx\n";
+ OS << " " << R.getName()
+ << "Attr(ASTContext &Ctx, const AttributeCommonInfo &CommonInfo";
+ OS << '\n';
for (auto const &ai : Args) {
if (!shouldEmitArg(ai)) continue;
OS << " , ";
@@ -2334,12 +2407,10 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
OS << "\n";
}
- OS << " , ";
- OS << "unsigned SI\n";
-
OS << " )\n";
- OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI, "
- << ( R.getValueAsBit("LateParsed") ? "true" : "false" );
+ OS << " : " << SuperName << "(Ctx, CommonInfo, ";
+ OS << "attr::" << R.getName() << ", "
+ << (R.getValueAsBit("LateParsed") ? "true" : "false");
if (Inheritable) {
OS << ", "
<< (R.getValueAsBit("InheritEvenIfAlreadyPresent") ? "true"
@@ -2371,14 +2442,12 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
emitCtor(true, true);
// Emit a constructor that takes all the non-fake arguments.
- if (HasFakeArg) {
+ if (HasFakeArg)
emitCtor(true, false);
- }
// Emit a constructor that takes all the non-fake, non-optional arguments.
- if (HasOptArg) {
+ if (HasOptArg)
emitCtor(false, false);
- }
OS << " " << R.getName() << "Attr *clone(ASTContext &C) const;\n";
OS << " void printPretty(raw_ostream &OS,\n"
@@ -2388,8 +2457,8 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
if (!ElideSpelling) {
assert(!SemanticToSyntacticMap.empty() && "Empty semantic mapping list");
OS << " Spelling getSemanticSpelling() const {\n";
- WriteSemanticSpellingSwitch("SpellingListIndex", SemanticToSyntacticMap,
- OS);
+ WriteSemanticSpellingSwitch("getAttributeSpellingListIndex()",
+ SemanticToSyntacticMap, OS);
OS << " }\n";
}
@@ -2422,7 +2491,7 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
}
// Emits the class method definitions for attributes.
-void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("Attribute classes' member function definitions", OS);
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
@@ -2443,15 +2512,15 @@ void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
OS << R.getName() << "Attr *" << R.getName()
<< "Attr::clone(ASTContext &C) const {\n";
- OS << " auto *A = new (C) " << R.getName() << "Attr(getLocation(), C";
+ OS << " auto *A = new (C) " << R.getName() << "Attr(C, *this";
for (auto const &ai : Args) {
OS << ", ";
ai->writeCloneArgs(OS);
}
- OS << ", getSpellingListIndex());\n";
+ OS << ");\n";
OS << " A->Inherited = Inherited;\n";
OS << " A->IsPackExpansion = IsPackExpansion;\n";
- OS << " A->Implicit = Implicit;\n";
+ OS << " A->setImplicit(Implicit);\n";
OS << " return A;\n}\n\n";
writePrettyPrintFunction(R, Args, OS);
@@ -2487,8 +2556,6 @@ void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
EmitFunc("printPretty(OS, Policy)");
}
-} // end namespace clang
-
static void emitAttrList(raw_ostream &OS, StringRef Class,
const std::vector<Record*> &AttrList) {
for (auto Cur : AttrList) {
@@ -2751,24 +2818,23 @@ void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
const Record &R = *Attr;
if (!R.getValueAsBit("ASTNode"))
continue;
-
+
OS << " case attr::" << R.getName() << ": {\n";
if (R.isSubClassOf(InhClass))
OS << " bool isInherited = Record.readInt();\n";
OS << " bool isImplicit = Record.readInt();\n";
- OS << " unsigned Spelling = Record.readInt();\n";
ArgRecords = R.getValueAsListOfDefs("Args");
Args.clear();
for (const auto *Arg : ArgRecords) {
Args.emplace_back(createArgument(*Arg, R.getName()));
Args.back()->writePCHReadDecls(OS);
}
- OS << " New = new (Context) " << R.getName() << "Attr(Range, Context";
+ OS << " New = new (Context) " << R.getName() << "Attr(Context, Info";
for (auto const &ri : Args) {
OS << ", ";
ri->writePCHReadArgs(OS);
}
- OS << ", Spelling);\n";
+ OS << ");\n";
if (R.isSubClassOf(InhClass))
OS << " cast<InheritableAttr>(New)->setInherited(isInherited);\n";
OS << " New->setImplicit(isImplicit);\n";
@@ -2798,7 +2864,6 @@ void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) {
if (R.isSubClassOf(InhClass))
OS << " Record.push_back(SA->isInherited());\n";
OS << " Record.push_back(A->isImplicit());\n";
- OS << " Record.push_back(A->getSpellingListIndex());\n";
for (const auto *Arg : Args)
createArgument(*Arg, R.getName())->writePCHWrite(OS);
@@ -3015,7 +3080,11 @@ void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("Code to translate different attribute spellings "
"into internal identifiers", OS);
- OS << " switch (AttrKind) {\n";
+ OS << " switch (getParsedKind()) {\n";
+ OS << " case IgnoredAttribute:\n";
+ OS << " case UnknownAttribute:\n";
+ OS << " case NoSemaHandlerAttribute:\n";
+ OS << " llvm_unreachable(\"Ignored/unknown shouldn't get here\");\n";
ParsedAttrMap Attrs = getParsedAttrList(Records);
for (const auto &I : Attrs) {
@@ -3024,16 +3093,7 @@ void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) {
OS << " case AT_" << I.first << ": {\n";
for (unsigned I = 0; I < Spellings.size(); ++ I) {
OS << " if (Name == \"" << Spellings[I].name() << "\" && "
- << "SyntaxUsed == "
- << StringSwitch<unsigned>(Spellings[I].variety())
- .Case("GNU", 0)
- .Case("CXX11", 1)
- .Case("C2x", 2)
- .Case("Declspec", 3)
- .Case("Microsoft", 4)
- .Case("Keyword", 5)
- .Case("Pragma", 6)
- .Default(0)
+ << "getSyntax() == AttributeCommonInfo::AS_" << Spellings[I].variety()
<< " && Scope == \"" << Spellings[I].nameSpace() << "\")\n"
<< " return " << I << ";\n";
}
@@ -3154,12 +3214,12 @@ void EmitClangAttrTemplateInstantiateHelper(const std::vector<Record *> &Attrs,
for (auto const &ai : Args)
ai->writeTemplateInstantiation(OS);
- OS << " return new (C) " << R.getName() << "Attr(A->getLocation(), C";
+ OS << " return new (C) " << R.getName() << "Attr(C, *A";
for (auto const &ai : Args) {
OS << ", ";
ai->writeTemplateInstantiationArgs(OS);
}
- OS << ", A->getSpellingListIndex());\n }\n";
+ OS << ");\n }\n";
}
OS << " } // end switch\n"
<< " llvm_unreachable(\"Unknown attribute!\");\n"
@@ -3477,7 +3537,7 @@ static std::string GenerateLangOptRequirements(const Record &R,
OS << " if (" << GenerateTestExpression(LangOpts) << ")\n";
OS << " return true;\n\n";
OS << " S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) ";
- OS << "<< Attr.getName();\n";
+ OS << "<< Attr;\n";
OS << " return false;\n";
OS << "}\n\n";
@@ -3671,10 +3731,10 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
// specific attribute, or MSP430-specific attribute. Additionally, an
// attribute can be spelled GNU<"dllexport"> and Declspec<"dllexport">
// for the same semantic attribute. Ultimately, we need to map each of
- // these to a single ParsedAttr::Kind value, but the StringMatcher
- // class cannot handle duplicate match strings. So we generate a list of
- // string to match based on the syntax, and emit multiple string matchers
- // depending on the syntax used.
+ // these to a single AttributeCommonInfo::Kind value, but the
+ // StringMatcher class cannot handle duplicate match strings. So we
+ // generate a list of string to match based on the syntax, and emit
+ // multiple string matchers depending on the syntax used.
std::string AttrName;
if (Attr.isSubClassOf("TargetSpecificAttr") &&
!Attr.isValueUnset("ParseKind")) {
@@ -3719,33 +3779,33 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
if (SemaHandler)
Matches->push_back(StringMatcher::StringPair(
- Spelling, "return ParsedAttr::AT_" + AttrName + ";"));
+ Spelling, "return AttributeCommonInfo::AT_" + AttrName + ";"));
else
Matches->push_back(StringMatcher::StringPair(
- Spelling, "return ParsedAttr::IgnoredAttribute;"));
+ Spelling, "return AttributeCommonInfo::IgnoredAttribute;"));
}
}
}
- OS << "static ParsedAttr::Kind getAttrKind(StringRef Name, ";
- OS << "ParsedAttr::Syntax Syntax) {\n";
- OS << " if (ParsedAttr::AS_GNU == Syntax) {\n";
+ OS << "static AttributeCommonInfo::Kind getAttrKind(StringRef Name, ";
+ OS << "AttributeCommonInfo::Syntax Syntax) {\n";
+ OS << " if (AttributeCommonInfo::AS_GNU == Syntax) {\n";
StringMatcher("Name", GNU, OS).Emit();
- OS << " } else if (ParsedAttr::AS_Declspec == Syntax) {\n";
+ OS << " } else if (AttributeCommonInfo::AS_Declspec == Syntax) {\n";
StringMatcher("Name", Declspec, OS).Emit();
- OS << " } else if (ParsedAttr::AS_Microsoft == Syntax) {\n";
+ OS << " } else if (AttributeCommonInfo::AS_Microsoft == Syntax) {\n";
StringMatcher("Name", Microsoft, OS).Emit();
- OS << " } else if (ParsedAttr::AS_CXX11 == Syntax) {\n";
+ OS << " } else if (AttributeCommonInfo::AS_CXX11 == Syntax) {\n";
StringMatcher("Name", CXX11, OS).Emit();
- OS << " } else if (ParsedAttr::AS_C2x == Syntax) {\n";
+ OS << " } else if (AttributeCommonInfo::AS_C2x == Syntax) {\n";
StringMatcher("Name", C2x, OS).Emit();
- OS << " } else if (ParsedAttr::AS_Keyword == Syntax || ";
- OS << "ParsedAttr::AS_ContextSensitiveKeyword == Syntax) {\n";
+ OS << " } else if (AttributeCommonInfo::AS_Keyword == Syntax || ";
+ OS << "AttributeCommonInfo::AS_ContextSensitiveKeyword == Syntax) {\n";
StringMatcher("Name", Keywords, OS).Emit();
- OS << " } else if (ParsedAttr::AS_Pragma == Syntax) {\n";
+ OS << " } else if (AttributeCommonInfo::AS_Pragma == Syntax) {\n";
StringMatcher("Name", Pragma, OS).Emit();
OS << " }\n";
- OS << " return ParsedAttr::UnknownAttribute;\n"
+ OS << " return AttributeCommonInfo::UnknownAttribute;\n"
<< "}\n";
}
diff --git a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
index c0dd70281a4d..fc79d59713d6 100644
--- a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
+++ b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
@@ -11,6 +11,8 @@
//
//===----------------------------------------------------------------------===//
+#include "TableGenBackends.h"
+
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/StringMatcher.h"
#include "llvm/TableGen/TableGenBackend.h"
@@ -18,8 +20,7 @@
using namespace llvm;
-namespace clang {
-void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("A list of commands useable in documentation "
"comments", OS);
@@ -105,7 +106,7 @@ static std::string MangleName(StringRef Str) {
return Mangled;
}
-void EmitClangCommentCommandList(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitClangCommentCommandList(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("A list of commands useable in documentation "
"comments", OS);
@@ -121,4 +122,3 @@ void EmitClangCommentCommandList(RecordKeeper &Records, raw_ostream &OS) {
OS << "COMMENT_COMMAND(" << MangledName << ")\n";
}
}
-} // end namespace clang
diff --git a/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp b/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp
index 81af5b4b95f1..ed3f4bd6ef6c 100644
--- a/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp
+++ b/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "TableGenBackends.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/TableGen/Error.h"
@@ -45,9 +46,8 @@ static bool translateCodePointToUTF8(unsigned CodePoint,
return true;
}
-namespace clang {
-void EmitClangCommentHTMLNamedCharacterReferences(RecordKeeper &Records,
- raw_ostream &OS) {
+void clang::EmitClangCommentHTMLNamedCharacterReferences(RecordKeeper &Records,
+ raw_ostream &OS) {
std::vector<Record *> Tags = Records.getAllDerivedDefinitions("NCR");
std::vector<StringMatcher::StringPair> NameToUTF8;
SmallString<32> CLiteral;
@@ -79,6 +79,3 @@ void EmitClangCommentHTMLNamedCharacterReferences(RecordKeeper &Records,
OS << " return StringRef();\n"
<< "}\n\n";
}
-
-} // end namespace clang
-
diff --git a/utils/TableGen/ClangDataCollectorsEmitter.cpp b/utils/TableGen/ClangDataCollectorsEmitter.cpp
index 4079efc80823..45082935c1f7 100644
--- a/utils/TableGen/ClangDataCollectorsEmitter.cpp
+++ b/utils/TableGen/ClangDataCollectorsEmitter.cpp
@@ -1,10 +1,10 @@
+#include "TableGenBackends.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
using namespace llvm;
-namespace clang {
-void EmitClangDataCollectors(RecordKeeper &RK, raw_ostream &OS) {
+void clang::EmitClangDataCollectors(RecordKeeper &RK, raw_ostream &OS) {
const auto &Defs = RK.getClasses();
for (const auto &Entry : Defs) {
Record &R = *Entry.second;
@@ -15,4 +15,3 @@ void EmitClangDataCollectors(RecordKeeper &RK, raw_ostream &OS) {
}
OS << "#undef DEF_ADD_DATA\n";
}
-} // end namespace clang
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
index 13e564e130ce..778375010041 100644
--- a/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "TableGenBackends.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerUnion.h"
@@ -1187,9 +1188,8 @@ static bool isRemark(const Record &Diag) {
/// ClangDiagsDefsEmitter - The top-level class emits .def files containing
/// declarations of Clang diagnostics.
-namespace clang {
-void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
- const std::string &Component) {
+void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
+ const std::string &Component) {
// Write the #if guard
if (!Component.empty()) {
std::string ComponentName = StringRef(Component).upper();
@@ -1288,7 +1288,6 @@ void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
OS << ")\n";
}
}
-} // end namespace clang
//===----------------------------------------------------------------------===//
// Warning Group Tables generation
@@ -1528,8 +1527,7 @@ static void emitCategoryTable(RecordKeeper &Records, raw_ostream &OS) {
OS << "#endif // GET_CATEGORY_TABLE\n\n";
}
-namespace clang {
-void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
// Compute a mapping from a DiagGroup to all of its parents.
DiagGroupParentMap DGParentMap(Records);
@@ -1565,7 +1563,6 @@ void EmitClangDiagGroups(RecordKeeper &Records, raw_ostream &OS) {
OS);
emitCategoryTable(Records, OS);
}
-} // end namespace clang
//===----------------------------------------------------------------------===//
// Diagnostic name index generation
@@ -1582,8 +1579,7 @@ struct RecordIndexElement
};
} // end anonymous namespace.
-namespace clang {
-void EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitClangDiagsIndexName(RecordKeeper &Records, raw_ostream &OS) {
const std::vector<Record*> &Diags =
Records.getAllDerivedDefinitions("Diagnostic");
@@ -1673,7 +1669,7 @@ void writeDiagnosticText(DiagnosticTextBuilder &Builder, const Record *R,
} // namespace
} // namespace docs
-void EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) {
using namespace docs;
// Get the documentation introduction paragraph.
@@ -1792,5 +1788,3 @@ void EmitClangDiagDocs(RecordKeeper &Records, raw_ostream &OS) {
OS << "\n";
}
}
-
-} // end namespace clang
diff --git a/utils/TableGen/ClangOpcodesEmitter.cpp b/utils/TableGen/ClangOpcodesEmitter.cpp
new file mode 100644
index 000000000000..e5bfac5ba1b6
--- /dev/null
+++ b/utils/TableGen/ClangOpcodesEmitter.cpp
@@ -0,0 +1,357 @@
+//=== ClangOpcodesEmitter.cpp - constexpr interpreter opcodes ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// These tablegen backends emit Clang AST node tables
+//
+//===----------------------------------------------------------------------===//
+
+#include "TableGenBackends.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/StringMatcher.h"
+#include "llvm/TableGen/TableGenBackend.h"
+
+using namespace llvm;
+
+namespace {
+class ClangOpcodesEmitter {
+ RecordKeeper &Records;
+ Record Root;
+ unsigned NumTypes;
+
+public:
+ ClangOpcodesEmitter(RecordKeeper &R)
+ : Records(R), Root("Opcode", SMLoc(), R),
+ NumTypes(Records.getAllDerivedDefinitions("Type").size()) {}
+
+ void run(raw_ostream &OS);
+
+private:
+ /// Emits the opcode name for the opcode enum.
+ /// The name is obtained by concatenating the name with the list of types.
+ void EmitEnum(raw_ostream &OS, StringRef N, Record *R);
+
+ /// Emits the switch case and the invocation in the interpreter.
+ void EmitInterp(raw_ostream &OS, StringRef N, Record *R);
+
+ /// Emits the disassembler.
+ void EmitDisasm(raw_ostream &OS, StringRef N, Record *R);
+
+ /// Emits the byte code emitter method.
+ void EmitEmitter(raw_ostream &OS, StringRef N, Record *R);
+
+ /// Emits the prototype.
+ void EmitProto(raw_ostream &OS, StringRef N, Record *R);
+
+ /// Emits the prototype to dispatch from a type.
+ void EmitGroup(raw_ostream &OS, StringRef N, Record *R);
+
+ /// Emits the evaluator method.
+ void EmitEval(raw_ostream &OS, StringRef N, Record *R);
+
+ void PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types);
+};
+
+void Enumerate(const Record *R,
+ StringRef N,
+ std::function<void(ArrayRef<Record *>, Twine)> &&F) {
+ llvm::SmallVector<Record *, 2> TypePath;
+ auto *Types = R->getValueAsListInit("Types");
+
+ std::function<void(size_t, const Twine &)> Rec;
+ Rec = [&TypePath, Types, &Rec, &F](size_t I, const Twine &ID) {
+ if (I >= Types->size()) {
+ F(TypePath, ID);
+ return;
+ }
+
+ if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) {
+ for (auto *Type : TypeClass->getDef()->getValueAsListOfDefs("Types")) {
+ TypePath.push_back(Type);
+ Rec(I + 1, ID + Type->getName());
+ TypePath.pop_back();
+ }
+ } else {
+ PrintFatalError("Expected a type class");
+ }
+ };
+ Rec(0, N);
+}
+
+} // namespace
+
+void ClangOpcodesEmitter::run(raw_ostream &OS) {
+ for (auto *Opcode : Records.getAllDerivedDefinitions(Root.getName())) {
+ // The name is the record name, unless overriden.
+ StringRef N = Opcode->getValueAsString("Name");
+ if (N.empty())
+ N = Opcode->getName();
+
+ EmitEnum(OS, N, Opcode);
+ EmitInterp(OS, N, Opcode);
+ EmitDisasm(OS, N, Opcode);
+ EmitProto(OS, N, Opcode);
+ EmitGroup(OS, N, Opcode);
+ EmitEmitter(OS, N, Opcode);
+ EmitEval(OS, N, Opcode);
+ }
+}
+
+void ClangOpcodesEmitter::EmitEnum(raw_ostream &OS, StringRef N, Record *R) {
+ OS << "#ifdef GET_OPCODE_NAMES\n";
+ Enumerate(R, N, [&OS](ArrayRef<Record *>, const Twine &ID) {
+ OS << "OP_" << ID << ",\n";
+ });
+ OS << "#endif\n";
+}
+
+void ClangOpcodesEmitter::EmitInterp(raw_ostream &OS, StringRef N, Record *R) {
+ OS << "#ifdef GET_INTERP\n";
+
+ Enumerate(R, N, [this, R, &OS, &N](ArrayRef<Record *> TS, const Twine &ID) {
+ bool CanReturn = R->getValueAsBit("CanReturn");
+ bool ChangesPC = R->getValueAsBit("ChangesPC");
+ auto Args = R->getValueAsListOfDefs("Args");
+
+ OS << "case OP_" << ID << ": {\n";
+
+ // Emit calls to read arguments.
+ for (size_t I = 0, N = Args.size(); I < N; ++I) {
+ OS << "\tauto V" << I;
+ OS << " = ";
+ OS << "PC.read<" << Args[I]->getValueAsString("Name") << ">();\n";
+ }
+
+ // Emit a call to the template method and pass arguments.
+ OS << "\tif (!" << N;
+ PrintTypes(OS, TS);
+ OS << "(S";
+ if (ChangesPC)
+ OS << ", PC";
+ else
+ OS << ", OpPC";
+ if (CanReturn)
+ OS << ", Result";
+ for (size_t I = 0, N = Args.size(); I < N; ++I)
+ OS << ", V" << I;
+ OS << "))\n";
+ OS << "\t\treturn false;\n";
+
+ // Bail out if interpreter returned.
+ if (CanReturn) {
+ OS << "\tif (!S.Current || S.Current->isRoot())\n";
+ OS << "\t\treturn true;\n";
+ }
+
+ OS << "\tcontinue;\n";
+ OS << "}\n";
+ });
+ OS << "#endif\n";
+}
+
+void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N, Record *R) {
+ OS << "#ifdef GET_DISASM\n";
+ Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) {
+ OS << "case OP_" << ID << ":\n";
+ OS << "\tPrintName(\"" << ID << "\");\n";
+ OS << "\tOS << \"\\t\"";
+
+ for (auto *Arg : R->getValueAsListOfDefs("Args"))
+ OS << " << PC.read<" << Arg->getValueAsString("Name") << ">() << \" \"";
+
+ OS << "<< \"\\n\";\n";
+ OS << "\tcontinue;\n";
+ });
+ OS << "#endif\n";
+}
+
+void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N, Record *R) {
+ if (R->getValueAsBit("HasCustomLink"))
+ return;
+
+ OS << "#ifdef GET_LINK_IMPL\n";
+ Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) {
+ auto Args = R->getValueAsListOfDefs("Args");
+
+ // Emit the list of arguments.
+ OS << "bool ByteCodeEmitter::emit" << ID << "(";
+ for (size_t I = 0, N = Args.size(); I < N; ++I)
+ OS << Args[I]->getValueAsString("Name") << " A" << I << ",";
+ OS << "const SourceInfo &L) {\n";
+
+ // Emit a call to write the opcodes.
+ OS << "\treturn emitOp<";
+ for (size_t I = 0, N = Args.size(); I < N; ++I) {
+ if (I != 0)
+ OS << ", ";
+ OS << Args[I]->getValueAsString("Name");
+ }
+ OS << ">(OP_" << ID;
+ for (size_t I = 0, N = Args.size(); I < N; ++I)
+ OS << ", A" << I;
+ OS << ", L);\n";
+ OS << "}\n";
+ });
+ OS << "#endif\n";
+}
+
+void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N, Record *R) {
+ OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
+ auto Args = R->getValueAsListOfDefs("Args");
+ Enumerate(R, N, [&OS, &Args](ArrayRef<Record *> TS, const Twine &ID) {
+ OS << "bool emit" << ID << "(";
+ for (auto *Arg : Args)
+ OS << Arg->getValueAsString("Name") << ", ";
+ OS << "const SourceInfo &);\n";
+ });
+
+ // Emit a template method for custom emitters to have less to implement.
+ auto TypeCount = R->getValueAsListInit("Types")->size();
+ if (R->getValueAsBit("HasCustomEval") && TypeCount) {
+ OS << "#if defined(GET_EVAL_PROTO)\n";
+ OS << "template<";
+ for (size_t I = 0; I < TypeCount; ++I) {
+ if (I != 0)
+ OS << ", ";
+ OS << "PrimType";
+ }
+ OS << ">\n";
+ OS << "bool emit" << N << "(";
+ for (auto *Arg : Args)
+ OS << Arg->getValueAsString("Name") << ", ";
+ OS << "const SourceInfo &);\n";
+ OS << "#endif\n";
+ }
+
+ OS << "#endif\n";
+}
+
+void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N, Record *R) {
+ if (!R->getValueAsBit("HasGroup"))
+ return;
+
+ auto *Types = R->getValueAsListInit("Types");
+ auto Args = R->getValueAsListOfDefs("Args");
+
+ // Emit the prototype of the group emitter in the header.
+ OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
+ OS << "bool emit" << N << "(";
+ for (size_t I = 0, N = Types->size(); I < N; ++I)
+ OS << "PrimType, ";
+ for (auto *Arg : Args)
+ OS << Arg->getValueAsString("Name") << ", ";
+ OS << "const SourceInfo &I);\n";
+ OS << "#endif\n";
+
+ // Emit the dispatch implementation in the source.
+ OS << "#if defined(GET_EVAL_IMPL) || defined(GET_LINK_IMPL)\n";
+ OS << "bool \n";
+ OS << "#if defined(GET_EVAL_IMPL)\n";
+ OS << "EvalEmitter\n";
+ OS << "#else\n";
+ OS << "ByteCodeEmitter\n";
+ OS << "#endif\n";
+ OS << "::emit" << N << "(";
+ for (size_t I = 0, N = Types->size(); I < N; ++I)
+ OS << "PrimType T" << I << ", ";
+ for (size_t I = 0, N = Args.size(); I < N; ++I)
+ OS << Args[I]->getValueAsString("Name") << " A" << I << ", ";
+ OS << "const SourceInfo &I) {\n";
+
+ std::function<void(size_t, const Twine &)> Rec;
+ llvm::SmallVector<Record *, 2> TS;
+ Rec = [this, &Rec, &OS, Types, &Args, R, &TS, N](size_t I, const Twine &ID) {
+ if (I >= Types->size()) {
+ // Print a call to the emitter method.
+ // Custom evaluator methods dispatch to template methods.
+ if (R->getValueAsBit("HasCustomEval")) {
+ OS << "#ifdef GET_LINK_IMPL\n";
+ OS << "return emit" << ID << "\n";
+ OS << "#else\n";
+ OS << "return emit" << N;
+ PrintTypes(OS, TS);
+ OS << "\n#endif\n";
+ } else {
+ OS << "return emit" << ID;
+ }
+
+ OS << "(";
+ for (size_t I = 0; I < Args.size(); ++I) {
+ OS << "A" << I << ", ";
+ }
+ OS << "I);\n";
+ return;
+ }
+
+ // Print a switch statement selecting T.
+ if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) {
+ OS << "switch (T" << I << "){\n";
+ auto Cases = TypeClass->getDef()->getValueAsListOfDefs("Types");
+ for (auto *Case : Cases) {
+ OS << "case PT_" << Case->getName() << ":\n";
+ TS.push_back(Case);
+ Rec(I + 1, ID + Case->getName());
+ TS.pop_back();
+ }
+ // Emit a default case if not all types are present.
+ if (Cases.size() < NumTypes)
+ OS << "default: llvm_unreachable(\"invalid type\");\n";
+ OS << "}\n";
+ OS << "llvm_unreachable(\"invalid enum value\");\n";
+ } else {
+ PrintFatalError("Expected a type class");
+ }
+ };
+ Rec(0, N);
+
+ OS << "}\n";
+ OS << "#endif\n";
+}
+
+void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N, Record *R) {
+ if (R->getValueAsBit("HasCustomEval"))
+ return;
+
+ OS << "#ifdef GET_EVAL_IMPL\n";
+ Enumerate(R, N, [this, R, &N, &OS](ArrayRef<Record *> TS, const Twine &ID) {
+ auto Args = R->getValueAsListOfDefs("Args");
+
+ OS << "bool EvalEmitter::emit" << ID << "(";
+ for (size_t I = 0, N = Args.size(); I < N; ++I)
+ OS << Args[I]->getValueAsString("Name") << " A" << I << ",";
+ OS << "const SourceInfo &L) {\n";
+ OS << "if (!isActive()) return true;\n";
+ OS << "CurrentSource = L;\n";
+
+ OS << "return " << N;
+ PrintTypes(OS, TS);
+ OS << "(S, OpPC";
+ for (size_t I = 0, N = Args.size(); I < N; ++I)
+ OS << ", A" << I;
+ OS << ");\n";
+ OS << "}\n";
+ });
+
+ OS << "#endif\n";
+}
+
+void ClangOpcodesEmitter::PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types) {
+ if (Types.empty())
+ return;
+ OS << "<";
+ for (size_t I = 0, N = Types.size(); I < N; ++I) {
+ if (I != 0)
+ OS << ", ";
+ OS << "PT_" << Types[I]->getName();
+ }
+ OS << ">";
+}
+
+void clang::EmitClangOpcodes(RecordKeeper &Records, raw_ostream &OS) {
+ ClangOpcodesEmitter(Records).run(OS);
+}
diff --git a/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp b/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
index 8d83b1c7fa6b..c8975d7bf615 100644
--- a/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
+++ b/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp
@@ -15,20 +15,49 @@
//
// For a successful lookup of e.g. the "cos" builtin, isOpenCLBuiltin("cos")
// returns a pair <Index, Len>.
-// OpenCLBuiltins[Index] to OpenCLBuiltins[Index + Len] contains the pairs
+// BuiltinTable[Index] to BuiltinTable[Index + Len] contains the pairs
// <SigIndex, SigLen> of the overloads of "cos".
-// OpenCLSignature[SigIndex] to OpenCLSignature[SigIndex + SigLen] contains
-// one of the signatures of "cos". The OpenCLSignature entry can be
-// referenced by other functions, i.e. "sin", since multiple OpenCL builtins
-// share the same signature.
+// SignatureTable[SigIndex] to SignatureTable[SigIndex + SigLen] contains
+// one of the signatures of "cos". The SignatureTable entry can be
+// referenced by other functions, e.g. "sin", to exploit the fact that
+// many OpenCL builtins share the same signature.
+//
+// The file generated by this TableGen emitter contains the following:
+//
+// * Structs and enums to represent types and function signatures.
+//
+// * OpenCLTypeStruct TypeTable[]
+// Type information for return types and arguments.
+//
+// * unsigned SignatureTable[]
+// A list of types representing function signatures. Each entry is an index
+// into the above TypeTable. Multiple entries following each other form a
+// signature, where the first entry is the return type and subsequent
+// entries are the argument types.
+//
+// * OpenCLBuiltinStruct BuiltinTable[]
+// Each entry represents one overload of an OpenCL builtin function and
+// consists of an index into the SignatureTable and the number of arguments.
+//
+// * std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef Name)
+// Find out whether a string matches an existing OpenCL builtin function
+// name and return an index into BuiltinTable and the number of overloads.
+//
+// * void OCL2Qual(ASTContext&, OpenCLTypeStruct, std::vector<QualType>&)
+// Convert an OpenCLTypeStruct type to a list of QualType instances.
+// One OpenCLTypeStruct can represent multiple types, primarily when using
+// GenTypes.
+//
//===----------------------------------------------------------------------===//
+#include "TableGenBackends.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
@@ -57,34 +86,49 @@ private:
// The output file.
raw_ostream &OS;
- // Emit the enums and structs.
+ // Helper function for BuiltinNameEmitter::EmitDeclarations. Generate enum
+ // definitions in the Output string parameter, and save their Record instances
+ // in the List parameter.
+ // \param Types (in) List containing the Types to extract.
+ // \param TypesSeen (inout) List containing the Types already extracted.
+ // \param Output (out) String containing the enums to emit in the output file.
+ // \param List (out) List containing the extracted Types, except the Types in
+ // TypesSeen.
+ void ExtractEnumTypes(std::vector<Record *> &Types,
+ StringMap<bool> &TypesSeen, std::string &Output,
+ std::vector<const Record *> &List);
+
+ // Emit the enum or struct used in the generated file.
+ // Populate the TypeList at the same time.
void EmitDeclarations();
- // Parse the Records generated by TableGen and populate OverloadInfo and
- // SignatureSet.
+ // Parse the Records generated by TableGen to populate the SignaturesList,
+ // FctOverloadMap and TypeMap.
void GetOverloads();
- // Emit the OpenCLSignature table. This table contains all possible
- // signatures, and is a struct OpenCLType. A signature is composed of a
- // return type (mandatory), followed by zero or more argument types.
+ // Emit the TypeTable containing all types used by OpenCL builtins.
+ void EmitTypeTable();
+
+ // Emit the SignatureTable. This table contains all the possible signatures.
+ // A signature is stored as a list of indexes of the TypeTable.
+ // The first index references the return type (mandatory), and the followings
+ // reference its arguments.
// E.g.:
- // // 12
- // { OCLT_uchar, 4, clang::LangAS::Default, false },
- // { OCLT_float, 4, clang::LangAS::Default, false },
- // This means that index 12 represents a signature
- // - returning a uchar vector of 4 elements, and
- // - taking as first argument a float vector of 4 elements.
+ // 15, 2, 15 can represent a function with the signature:
+ // int func(float, int)
+ // The "int" type being at the index 15 in the TypeTable.
void EmitSignatureTable();
- // Emit the OpenCLBuiltins table. This table contains all overloads of
+ // Emit the BuiltinTable table. This table contains all the overloads of
// each function, and is a struct OpenCLBuiltinDecl.
// E.g.:
- // // acos
- // { 2, 0, "", 100 },
- // This means that the signature of this acos overload is defined in OpenCL
- // version 1.0 (100) and does not belong to any extension (""). It has a
- // 1 argument (+1 for the return type), stored at index 0 in the
- // OpenCLSignature table.
+ // // 891 convert_float2_rtn
+ // { 58, 2, 100, 0 },
+ // This means that the signature of this convert_float2_rtn overload has
+ // 1 argument (+1 for the return type), stored at index 58 in
+ // the SignatureTable. The last two values represent the minimum (1.0) and
+ // maximum (0, meaning no max version) OpenCL version in which this overload
+ // is supported.
void EmitBuiltinTable();
// Emit a StringMatcher function to check whether a function name is an
@@ -102,20 +146,30 @@ private:
// <<float>, 5>,
// ...
// <<double, double>, 35>.
- std::vector<std::pair<std::vector<Record *>, unsigned>> SignatureSet;
+ std::vector<std::pair<std::vector<Record *>, unsigned>> SignaturesList;
// Map the name of a builtin function to its prototypes (instances of the
// TableGen "Builtin" class).
// Each prototype is registered as a pair of:
// <pointer to the "Builtin" instance,
- // cumulative index of the associated signature in the SignatureSet>
+ // cumulative index of the associated signature in the SignaturesList>
// E.g.: The function cos: (float cos(float), double cos(double), ...)
// <"cos", <<ptrToPrototype0, 5>,
- // <ptrToPrototype1, 35>>
- // <ptrToPrototype2, 79>>
+ // <ptrToPrototype1, 35>,
+ // <ptrToPrototype2, 79>>
// ptrToPrototype1 has the following signature: <double, double>
MapVector<StringRef, std::vector<std::pair<const Record *, unsigned>>>
- OverloadInfo;
+ FctOverloadMap;
+
+ // Contains the map of OpenCL types to their index in the TypeTable.
+ MapVector<const Record *, unsigned> TypeMap;
+
+ // List of OpenCL type names in the same order as in enum OpenCLTypeID.
+ // This list does not contain generic types.
+ std::vector<const Record *> TypeList;
+
+ // Same as TypeList, but for generic types only.
+ std::vector<const Record *> GenTypeList;
};
} // namespace
@@ -125,12 +179,14 @@ void BuiltinNameEmitter::Emit() {
OS << "#include \"llvm/ADT/StringRef.h\"\n";
OS << "using namespace clang;\n\n";
+ // Emit enums and structs.
EmitDeclarations();
GetOverloads();
+ // Emit tables.
+ EmitTypeTable();
EmitSignatureTable();
-
EmitBuiltinTable();
EmitStringMatcher();
@@ -138,100 +194,226 @@ void BuiltinNameEmitter::Emit() {
EmitQualTypeFinder();
}
+void BuiltinNameEmitter::ExtractEnumTypes(std::vector<Record *> &Types,
+ StringMap<bool> &TypesSeen,
+ std::string &Output,
+ std::vector<const Record *> &List) {
+ raw_string_ostream SS(Output);
+
+ for (const auto *T : Types) {
+ if (TypesSeen.find(T->getValueAsString("Name")) == TypesSeen.end()) {
+ SS << " OCLT_" + T->getValueAsString("Name") << ",\n";
+ // Save the type names in the same order as their enum value. Note that
+ // the Record can be a VectorType or something else, only the name is
+ // important.
+ List.push_back(T);
+ TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true));
+ }
+ }
+ SS.flush();
+}
+
void BuiltinNameEmitter::EmitDeclarations() {
+ // Enum of scalar type names (float, int, ...) and generic type sets.
OS << "enum OpenCLTypeID {\n";
- std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type");
+
StringMap<bool> TypesSeen;
- for (const auto *T : Types) {
- if (TypesSeen.find(T->getValueAsString("Name")) == TypesSeen.end())
- OS << " OCLT_" + T->getValueAsString("Name") << ",\n";
- TypesSeen.insert(std::make_pair(T->getValueAsString("Name"), true));
- }
+ std::string GenTypeEnums;
+ std::string TypeEnums;
+
+ // Extract generic types and non-generic types separately, to keep
+ // gentypes at the end of the enum which simplifies the special handling
+ // for gentypes in SemaLookup.
+ std::vector<Record *> GenTypes =
+ Records.getAllDerivedDefinitions("GenericType");
+ ExtractEnumTypes(GenTypes, TypesSeen, GenTypeEnums, GenTypeList);
+
+ std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type");
+ ExtractEnumTypes(Types, TypesSeen, TypeEnums, TypeList);
+
+ OS << TypeEnums;
+ OS << GenTypeEnums;
OS << "};\n";
+ // Structure definitions.
OS << R"(
+// Image access qualifier.
+enum OpenCLAccessQual : unsigned char {
+ OCLAQ_None,
+ OCLAQ_ReadOnly,
+ OCLAQ_WriteOnly,
+ OCLAQ_ReadWrite
+};
-// Type used in a prototype of an OpenCL builtin function.
-struct OpenCLType {
- // A type (e.g.: float, int, ...)
- OpenCLTypeID ID;
- // Size of vector (if applicable)
- unsigned VectorWidth;
- // Address space of the pointer (if applicable)
- LangAS AS;
- // Whether the type is a pointer
- bool isPointer;
+// Represents a return type or argument type.
+struct OpenCLTypeStruct {
+ // A type (e.g. float, int, ...).
+ const OpenCLTypeID ID;
+ // Vector size (if applicable; 0 for scalars and generic types).
+ const unsigned VectorWidth;
+ // 0 if the type is not a pointer.
+ const bool IsPointer;
+ // 0 if the type is not const.
+ const bool IsConst;
+ // 0 if the type is not volatile.
+ const bool IsVolatile;
+ // Access qualifier.
+ const OpenCLAccessQual AccessQualifier;
+ // Address space of the pointer (if applicable).
+ const LangAS AS;
};
// One overload of an OpenCL builtin function.
-struct OpenCLBuiltinDecl {
- // Number of arguments for the signature
- unsigned NumArgs;
- // Index in the OpenCLSignature table to get the required types
- unsigned ArgTableIndex;
- // Extension to which it belongs (e.g. cl_khr_subgroups)
- const char *Extension;
- // Version in which it was introduced (e.g. CL20)
- unsigned Version;
+struct OpenCLBuiltinStruct {
+ // Index of the signature in the OpenCLTypeStruct table.
+ const unsigned SigTableIndex;
+ // Entries between index SigTableIndex and (SigTableIndex + NumTypes - 1) in
+ // the SignatureTable represent the complete signature. The first type at
+ // index SigTableIndex is the return type.
+ const unsigned NumTypes;
+ // First OpenCL version in which this overload was introduced (e.g. CL20).
+ const unsigned short MinVersion;
+ // First OpenCL version in which this overload was removed (e.g. CL20).
+ const unsigned short MaxVersion;
};
)";
}
+// Verify that the combination of GenTypes in a signature is supported.
+// To simplify the logic for creating overloads in SemaLookup, only allow
+// a signature to contain different GenTypes if these GenTypes represent
+// the same number of actual scalar or vector types.
+//
+// Exit with a fatal error if an unsupported construct is encountered.
+static void VerifySignature(const std::vector<Record *> &Signature,
+ const Record *BuiltinRec) {
+ unsigned GenTypeVecSizes = 1;
+ unsigned GenTypeTypes = 1;
+
+ for (const auto *T : Signature) {
+ // Check all GenericType arguments in this signature.
+ if (T->isSubClassOf("GenericType")) {
+ // Check number of vector sizes.
+ unsigned NVecSizes =
+ T->getValueAsDef("VectorList")->getValueAsListOfInts("List").size();
+ if (NVecSizes != GenTypeVecSizes && NVecSizes != 1) {
+ if (GenTypeVecSizes > 1) {
+ // We already saw a gentype with a different number of vector sizes.
+ PrintFatalError(BuiltinRec->getLoc(),
+ "number of vector sizes should be equal or 1 for all gentypes "
+ "in a declaration");
+ }
+ GenTypeVecSizes = NVecSizes;
+ }
+
+ // Check number of data types.
+ unsigned NTypes =
+ T->getValueAsDef("TypeList")->getValueAsListOfDefs("List").size();
+ if (NTypes != GenTypeTypes && NTypes != 1) {
+ if (GenTypeTypes > 1) {
+ // We already saw a gentype with a different number of types.
+ PrintFatalError(BuiltinRec->getLoc(),
+ "number of types should be equal or 1 for all gentypes "
+ "in a declaration");
+ }
+ GenTypeTypes = NTypes;
+ }
+ }
+ }
+}
+
void BuiltinNameEmitter::GetOverloads() {
+ // Populate the TypeMap.
+ std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type");
+ unsigned I = 0;
+ for (const auto &T : Types) {
+ TypeMap.insert(std::make_pair(T, I++));
+ }
+
+ // Populate the SignaturesList and the FctOverloadMap.
unsigned CumulativeSignIndex = 0;
std::vector<Record *> Builtins = Records.getAllDerivedDefinitions("Builtin");
for (const auto *B : Builtins) {
StringRef BName = B->getValueAsString("Name");
- if (OverloadInfo.find(BName) == OverloadInfo.end()) {
- OverloadInfo.insert(std::make_pair(
+ if (FctOverloadMap.find(BName) == FctOverloadMap.end()) {
+ FctOverloadMap.insert(std::make_pair(
BName, std::vector<std::pair<const Record *, unsigned>>{}));
}
auto Signature = B->getValueAsListOfDefs("Signature");
+ // Reuse signatures to avoid unnecessary duplicates.
auto it =
- std::find_if(SignatureSet.begin(), SignatureSet.end(),
+ std::find_if(SignaturesList.begin(), SignaturesList.end(),
[&](const std::pair<std::vector<Record *>, unsigned> &a) {
return a.first == Signature;
});
unsigned SignIndex;
- if (it == SignatureSet.end()) {
- SignatureSet.push_back(std::make_pair(Signature, CumulativeSignIndex));
+ if (it == SignaturesList.end()) {
+ VerifySignature(Signature, B);
+ SignaturesList.push_back(std::make_pair(Signature, CumulativeSignIndex));
SignIndex = CumulativeSignIndex;
CumulativeSignIndex += Signature.size();
} else {
SignIndex = it->second;
}
- OverloadInfo[BName].push_back(std::make_pair(B, SignIndex));
+ FctOverloadMap[BName].push_back(std::make_pair(B, SignIndex));
}
}
+void BuiltinNameEmitter::EmitTypeTable() {
+ OS << "static const OpenCLTypeStruct TypeTable[] = {\n";
+ for (const auto &T : TypeMap) {
+ const char *AccessQual =
+ StringSwitch<const char *>(T.first->getValueAsString("AccessQualifier"))
+ .Case("RO", "OCLAQ_ReadOnly")
+ .Case("WO", "OCLAQ_WriteOnly")
+ .Case("RW", "OCLAQ_ReadWrite")
+ .Default("OCLAQ_None");
+
+ OS << " // " << T.second << "\n"
+ << " {OCLT_" << T.first->getValueAsString("Name") << ", "
+ << T.first->getValueAsInt("VecWidth") << ", "
+ << T.first->getValueAsBit("IsPointer") << ", "
+ << T.first->getValueAsBit("IsConst") << ", "
+ << T.first->getValueAsBit("IsVolatile") << ", "
+ << AccessQual << ", "
+ << T.first->getValueAsString("AddrSpace") << "},\n";
+ }
+ OS << "};\n\n";
+}
+
void BuiltinNameEmitter::EmitSignatureTable() {
- OS << "static const OpenCLType OpenCLSignature[] = {\n";
- for (auto &P : SignatureSet) {
- OS << "// " << P.second << "\n";
- for (Record *R : P.first) {
- OS << "{ OCLT_" << R->getValueAsString("Name") << ", "
- << R->getValueAsInt("VecWidth") << ", "
- << R->getValueAsString("AddrSpace") << ", "
- << R->getValueAsBit("IsPointer") << "},";
- OS << "\n";
+ // Store a type (e.g. int, float, int2, ...). The type is stored as an index
+ // of a struct OpenCLType table. Multiple entries following each other form a
+ // signature.
+ OS << "static const unsigned SignatureTable[] = {\n";
+ for (const auto &P : SignaturesList) {
+ OS << " // " << P.second << "\n ";
+ for (const Record *R : P.first) {
+ OS << TypeMap.find(R)->second << ", ";
}
+ OS << "\n";
}
OS << "};\n\n";
}
void BuiltinNameEmitter::EmitBuiltinTable() {
- OS << "static const OpenCLBuiltinDecl OpenCLBuiltins[] = {\n";
- for (auto &i : OverloadInfo) {
- StringRef Name = i.first;
- OS << "// " << Name << "\n";
- for (auto &Overload : i.second) {
- OS << " { " << Overload.first->getValueAsListOfDefs("Signature").size()
- << ", " << Overload.second << ", " << '"'
- << Overload.first->getValueAsString("Extension") << "\", "
- << Overload.first->getValueAsDef("Version")->getValueAsInt("Version")
+ unsigned Index = 0;
+
+ OS << "static const OpenCLBuiltinStruct BuiltinTable[] = {\n";
+ for (const auto &FOM : FctOverloadMap) {
+
+ OS << " // " << (Index + 1) << ": " << FOM.first << "\n";
+
+ for (const auto &Overload : FOM.second) {
+ OS << " { " << Overload.second << ", "
+ << Overload.first->getValueAsListOfDefs("Signature").size() << ", "
+ << Overload.first->getValueAsDef("MinVersion")->getValueAsInt("ID")
+ << ", "
+ << Overload.first->getValueAsDef("MaxVersion")->getValueAsInt("ID")
<< " },\n";
+ Index++;
}
}
OS << "};\n\n";
@@ -240,7 +422,7 @@ void BuiltinNameEmitter::EmitBuiltinTable() {
void BuiltinNameEmitter::EmitStringMatcher() {
std::vector<StringMatcher::StringPair> ValidBuiltins;
unsigned CumulativeIndex = 1;
- for (auto &i : OverloadInfo) {
+ for (auto &i : FctOverloadMap) {
auto &Ov = i.second;
std::string RetStmt;
raw_string_ostream SS(RetStmt);
@@ -253,30 +435,137 @@ void BuiltinNameEmitter::EmitStringMatcher() {
}
OS << R"(
-// Return 0 if name is not a recognized OpenCL builtin, or an index
-// into a table of declarations if it is an OpenCL builtin.
-static std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef name) {
+// Find out whether a string matches an existing OpenCL builtin function name.
+// Returns: A pair <0, 0> if no name matches.
+// A pair <Index, Len> indexing the BuiltinTable if the name is
+// matching an OpenCL builtin function.
+static std::pair<unsigned, unsigned> isOpenCLBuiltin(llvm::StringRef Name) {
)";
- StringMatcher("name", ValidBuiltins, OS).Emit(0, true);
+ StringMatcher("Name", ValidBuiltins, OS).Emit(0, true);
OS << " return std::make_pair(0, 0);\n";
- OS << "}\n";
+ OS << "} // isOpenCLBuiltin\n";
}
void BuiltinNameEmitter::EmitQualTypeFinder() {
OS << R"(
-static QualType OCL2Qual(ASTContext &Context, OpenCLType Ty) {
- QualType RT = Context.VoidTy;
- switch (Ty.ID) {
+// Convert an OpenCLTypeStruct type to a list of QualTypes.
+// Generic types represent multiple types and vector sizes, thus a vector
+// is returned. The conversion is done in two steps:
+// Step 1: A switch statement fills a vector with scalar base types for the
+// Cartesian product of (vector sizes) x (types) for generic types,
+// or a single scalar type for non generic types.
+// Step 2: Qualifiers and other type properties such as vector size are
+// applied.
+static void OCL2Qual(ASTContext &Context, const OpenCLTypeStruct &Ty,
+ llvm::SmallVectorImpl<QualType> &QT) {
+ // Number of scalar types in the GenType.
+ unsigned GenTypeNumTypes;
+ // Pointer to the list of vector sizes for the GenType.
+ llvm::ArrayRef<unsigned> GenVectorSizes;
)";
+ // Generate list of vector sizes for each generic type.
+ for (const auto *VectList : Records.getAllDerivedDefinitions("IntList")) {
+ OS << " constexpr unsigned List"
+ << VectList->getValueAsString("Name") << "[] = {";
+ for (const auto V : VectList->getValueAsListOfInts("List")) {
+ OS << V << ", ";
+ }
+ OS << "};\n";
+ }
+
+ // Step 1.
+ // Start of switch statement over all types.
+ OS << "\n switch (Ty.ID) {\n";
+
+ // Switch cases for image types (Image2d, Image3d, ...)
+ std::vector<Record *> ImageTypes =
+ Records.getAllDerivedDefinitions("ImageType");
+
+ // Map an image type name to its 3 access-qualified types (RO, WO, RW).
+ std::map<StringRef, SmallVector<Record *, 3>> ImageTypesMap;
+ for (auto *IT : ImageTypes) {
+ auto Entry = ImageTypesMap.find(IT->getValueAsString("Name"));
+ if (Entry == ImageTypesMap.end()) {
+ SmallVector<Record *, 3> ImageList;
+ ImageList.push_back(IT);
+ ImageTypesMap.insert(
+ std::make_pair(IT->getValueAsString("Name"), ImageList));
+ } else {
+ Entry->second.push_back(IT);
+ }
+ }
+
+ // Emit the cases for the image types. For an image type name, there are 3
+ // corresponding QualTypes ("RO", "WO", "RW"). The "AccessQualifier" field
+ // tells which one is needed. Emit a switch statement that puts the
+ // corresponding QualType into "QT".
+ for (const auto &ITE : ImageTypesMap) {
+ OS << " case OCLT_" << ITE.first.str() << ":\n"
+ << " switch (Ty.AccessQualifier) {\n"
+ << " case OCLAQ_None:\n"
+ << " llvm_unreachable(\"Image without access qualifier\");\n";
+ for (const auto &Image : ITE.second) {
+ OS << StringSwitch<const char *>(
+ Image->getValueAsString("AccessQualifier"))
+ .Case("RO", " case OCLAQ_ReadOnly:\n")
+ .Case("WO", " case OCLAQ_WriteOnly:\n")
+ .Case("RW", " case OCLAQ_ReadWrite:\n")
+ << " QT.push_back(Context."
+ << Image->getValueAsDef("QTName")->getValueAsString("Name") << ");\n"
+ << " break;\n";
+ }
+ OS << " }\n"
+ << " break;\n";
+ }
+
+ // Switch cases for generic types.
+ for (const auto *GenType : Records.getAllDerivedDefinitions("GenericType")) {
+ OS << " case OCLT_" << GenType->getValueAsString("Name") << ":\n";
+ OS << " QT.append({";
+
+ // Build the Cartesian product of (vector sizes) x (types). Only insert
+ // the plain scalar types for now; other type information such as vector
+ // size and type qualifiers will be added after the switch statement.
+ for (unsigned I = 0; I < GenType->getValueAsDef("VectorList")
+ ->getValueAsListOfInts("List")
+ .size();
+ I++) {
+ for (const auto *T :
+ GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List")) {
+ OS << "Context."
+ << T->getValueAsDef("QTName")->getValueAsString("Name") << ", ";
+ }
+ }
+ OS << "});\n";
+ // GenTypeNumTypes is the number of types in the GenType
+ // (e.g. float/double/half).
+ OS << " GenTypeNumTypes = "
+ << GenType->getValueAsDef("TypeList")->getValueAsListOfDefs("List")
+ .size()
+ << ";\n";
+ // GenVectorSizes is the list of vector sizes for this GenType.
+ // QT contains GenTypeNumTypes * #GenVectorSizes elements.
+ OS << " GenVectorSizes = List"
+ << GenType->getValueAsDef("VectorList")->getValueAsString("Name")
+ << ";\n";
+ OS << " break;\n";
+ }
+
+ // Switch cases for non generic, non image types (int, int4, float, ...).
+ // Only insert the plain scalar type; vector information and type qualifiers
+ // are added in step 2.
std::vector<Record *> Types = Records.getAllDerivedDefinitions("Type");
StringMap<bool> TypesSeen;
for (const auto *T : Types) {
+ // Check this is not an image type
+ if (ImageTypesMap.find(T->getValueAsString("Name")) != ImageTypesMap.end())
+ continue;
// Check we have not seen this Type
if (TypesSeen.find(T->getValueAsString("Name")) != TypesSeen.end())
continue;
@@ -284,35 +573,74 @@ static QualType OCL2Qual(ASTContext &Context, OpenCLType Ty) {
// Check the Type does not have an "abstract" QualType
auto QT = T->getValueAsDef("QTName");
- if (QT->getValueAsString("Name") == "null")
+ if (QT->getValueAsBit("IsAbstract") == 1)
continue;
+ // Emit the cases for non generic, non image types.
+ OS << " case OCLT_" << T->getValueAsString("Name") << ":\n";
+ OS << " QT.push_back(Context." << QT->getValueAsString("Name")
+ << ");\n";
+ OS << " break;\n";
+ }
- OS << " case OCLT_" << T->getValueAsString("Name") << ":\n";
- OS << " RT = Context." << QT->getValueAsString("Name") << ";\n";
- OS << " break;\n";
+ // End of switch statement.
+ OS << " default:\n"
+ << " llvm_unreachable(\"OpenCL builtin type not handled yet\");\n"
+ << " } // end of switch (Ty.ID)\n\n";
+
+ // Step 2.
+ // Add ExtVector types if this was a generic type, as the switch statement
+ // above only populated the list with scalar types. This completes the
+ // construction of the Cartesian product of (vector sizes) x (types).
+ OS << " // Construct the different vector types for each generic type.\n";
+ OS << " if (Ty.ID >= " << TypeList.size() << ") {";
+ OS << R"(
+ for (unsigned I = 0; I < QT.size(); I++) {
+ // For scalars, size is 1.
+ if (GenVectorSizes[I / GenTypeNumTypes] != 1) {
+ QT[I] = Context.getExtVectorType(QT[I],
+ GenVectorSizes[I / GenTypeNumTypes]);
+ }
+ }
}
- OS << " }\n";
+)";
- // Special cases
+ // Assign the right attributes to the types (e.g. vector size).
OS << R"(
- if (Ty.VectorWidth > 0)
- RT = Context.getExtVectorType(RT, Ty.VectorWidth);
+ // Set vector size for non-generic vector types.
+ if (Ty.VectorWidth > 1) {
+ for (unsigned Index = 0; Index < QT.size(); Index++) {
+ QT[Index] = Context.getExtVectorType(QT[Index], Ty.VectorWidth);
+ }
+ }
+
+ if (Ty.IsVolatile != 0) {
+ for (unsigned Index = 0; Index < QT.size(); Index++) {
+ QT[Index] = Context.getVolatileType(QT[Index]);
+ }
+ }
- if (Ty.isPointer) {
- RT = Context.getAddrSpaceQualType(RT, Ty.AS);
- RT = Context.getPointerType(RT);
+ if (Ty.IsConst != 0) {
+ for (unsigned Index = 0; Index < QT.size(); Index++) {
+ QT[Index] = Context.getConstType(QT[Index]);
+ }
}
- return RT;
-}
+ // Transform the type to a pointer as the last step, if necessary.
+ // Builtin functions only have pointers on [const|volatile], no
+ // [const|volatile] pointers, so this is ok to do it as a last step.
+ if (Ty.IsPointer != 0) {
+ for (unsigned Index = 0; Index < QT.size(); Index++) {
+ QT[Index] = Context.getAddrSpaceQualType(QT[Index], Ty.AS);
+ QT[Index] = Context.getPointerType(QT[Index]);
+ }
+ }
)";
-}
-namespace clang {
+ // End of the "OCL2Qual" function.
+ OS << "\n} // OCL2Qual\n";
+}
-void EmitClangOpenCLBuiltins(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitClangOpenCLBuiltins(RecordKeeper &Records, raw_ostream &OS) {
BuiltinNameEmitter NameChecker(Records, OS);
NameChecker.Emit();
}
-
-} // end namespace clang
diff --git a/utils/TableGen/ClangOptionDocEmitter.cpp b/utils/TableGen/ClangOptionDocEmitter.cpp
index 7027113c4fa8..b944ad9608f5 100644
--- a/utils/TableGen/ClangOptionDocEmitter.cpp
+++ b/utils/TableGen/ClangOptionDocEmitter.cpp
@@ -8,6 +8,7 @@
//
//===----------------------------------------------------------------------===//
+#include "TableGenBackends.h"
#include "llvm/TableGen/Error.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
@@ -21,8 +22,6 @@
using namespace llvm;
-namespace clang {
-namespace docs {
namespace {
struct DocumentedOption {
Record *Option;
@@ -380,11 +379,8 @@ void emitDocumentation(int Depth, const Documentation &Doc,
}
} // namespace
-} // namespace docs
-
-void EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS) {
- using namespace docs;
+void clang::EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS) {
const Record *DocInfo = Records.getDef("GlobalDocumentation");
if (!DocInfo) {
PrintFatalError("The GlobalDocumentation top-level definition is missing, "
@@ -396,4 +392,3 @@ void EmitClangOptDocs(RecordKeeper &Records, raw_ostream &OS) {
emitDocumentation(0, extractDocumentation(Records), DocInfo, OS);
}
-} // end namespace clang
diff --git a/utils/TableGen/ClangSACheckersEmitter.cpp b/utils/TableGen/ClangSACheckersEmitter.cpp
index 7dd0895b76d4..feefbeb41138 100644
--- a/utils/TableGen/ClangSACheckersEmitter.cpp
+++ b/utils/TableGen/ClangSACheckersEmitter.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "TableGenBackends.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
@@ -174,8 +175,7 @@ static void printOption(llvm::raw_ostream &OS, StringRef FullName,
OS << "true";
}
-namespace clang {
-void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
std::vector<Record*> packages = Records.getAllDerivedDefinitions("Package");
@@ -315,4 +315,3 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
OS << "#endif // GET_CHECKER_OPTIONS\n"
"\n";
}
-} // end namespace clang
diff --git a/utils/TableGen/ClangTypeNodesEmitter.cpp b/utils/TableGen/ClangTypeNodesEmitter.cpp
new file mode 100644
index 000000000000..c9986c8fa496
--- /dev/null
+++ b/utils/TableGen/ClangTypeNodesEmitter.cpp
@@ -0,0 +1,220 @@
+//=== ClangTypeNodesEmitter.cpp - Generate type node tables -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This tblgen backend emits the node table (the .def file) for Clang
+// type nodes.
+//
+// This file defines the AST type info database. Each type node is
+// enumerated by providing its name (e.g., "Builtin" or "Enum") and
+// base class (e.g., "Type" or "TagType"). Depending on where in the
+// abstract syntax tree the type will show up, the enumeration uses
+// one of five different macros:
+//
+// TYPE(Class, Base) - A type that can show up anywhere in the AST,
+// and might be dependent, canonical, or non-canonical. All clients
+// will need to understand these types.
+//
+// ABSTRACT_TYPE(Class, Base) - An abstract class that shows up in
+// the type hierarchy but has no concrete instances.
+//
+// NON_CANONICAL_TYPE(Class, Base) - A type that can show up
+// anywhere in the AST but will never be a part of a canonical
+// type. Clients that only need to deal with canonical types
+// (ignoring, e.g., typedefs and other type aliases used for
+// pretty-printing) can ignore these types.
+//
+// DEPENDENT_TYPE(Class, Base) - A type that will only show up
+// within a C++ template that has not been instantiated, e.g., a
+// type that is always dependent. Clients that do not need to deal
+// with uninstantiated C++ templates can ignore these types.
+//
+// NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) - A type that
+// is non-canonical unless it is dependent. Defaults to TYPE because
+// it is neither reliably dependent nor reliably non-canonical.
+//
+// There is a sixth macro, independent of the others. Most clients
+// will not need to use it.
+//
+// LEAF_TYPE(Class) - A type that never has inner types. Clients
+// which can operate on such types more efficiently may wish to do so.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <set>
+#include <string>
+#include <vector>
+#include "TableGenBackends.h"
+
+using namespace llvm;
+
+// These are spellings in the generated output.
+#define TypeMacroName "TYPE"
+#define AbstractTypeMacroName "ABSTRACT_TYPE"
+#define DependentTypeMacroName "DEPENDENT_TYPE"
+#define NonCanonicalTypeMacroName "NON_CANONICAL_TYPE"
+#define NonCanonicalUnlessDependentTypeMacroName "NON_CANONICAL_UNLESS_DEPENDENT_TYPE"
+#define TypeMacroArgs "(Class, Base)"
+#define LastTypeMacroName "LAST_TYPE"
+#define LeafTypeMacroName "LEAF_TYPE"
+
+// These are spellings in the tblgen file.
+// (Type is also used for the spelling of the AST class.)
+#define TypeClassName "Type"
+#define DerivedTypeClassName "DerivedType"
+#define AlwaysDependentClassName "AlwaysDependent"
+#define NeverCanonicalClassName "NeverCanonical"
+#define NeverCanonicalUnlessDependentClassName "NeverCanonicalUnlessDependent"
+#define LeafTypeClassName "LeafType"
+#define AbstractFieldName "Abstract"
+#define BaseFieldName "Base"
+
+static StringRef getIdForType(Record *type) {
+ // The record name is expected to be the full C++ class name,
+ // including "Type". Check for that and strip it off.
+ auto fullName = type->getName();
+ if (!fullName.endswith("Type"))
+ PrintFatalError(type->getLoc(), "name of Type node doesn't end in Type");
+ return fullName.drop_back(4);
+}
+
+namespace {
+class TypeNodeEmitter {
+ RecordKeeper &Records;
+ raw_ostream &Out;
+ const std::vector<Record*> Types;
+ std::vector<StringRef> MacrosToUndef;
+
+public:
+ TypeNodeEmitter(RecordKeeper &records, raw_ostream &out)
+ : Records(records), Out(out),
+ Types(Records.getAllDerivedDefinitions("Type")) {
+ }
+
+ void emit();
+
+private:
+ void emitFallbackDefine(StringRef macroName, StringRef fallbackMacroName,
+ StringRef args);
+
+ void emitNodeInvocations();
+ void emitLastNodeInvocation();
+ void emitLeafNodeInvocations();
+
+ void addMacroToUndef(StringRef macroName);
+ void emitUndefs();
+};
+}
+
+void TypeNodeEmitter::emit() {
+ if (Types.empty())
+ PrintFatalError("no Type records in input!");
+
+ emitSourceFileHeader("An x-macro database of Clang type nodes", Out);
+
+ // Preamble
+ addMacroToUndef(TypeMacroName);
+ addMacroToUndef(AbstractTypeMacroName);
+ emitFallbackDefine(AbstractTypeMacroName, TypeMacroName, TypeMacroArgs);
+ emitFallbackDefine(NonCanonicalTypeMacroName, TypeMacroName, TypeMacroArgs);
+ emitFallbackDefine(DependentTypeMacroName, TypeMacroName, TypeMacroArgs);
+ emitFallbackDefine(NonCanonicalUnlessDependentTypeMacroName, TypeMacroName,
+ TypeMacroArgs);
+
+ // Invocations.
+ emitNodeInvocations();
+ emitLastNodeInvocation();
+ emitLeafNodeInvocations();
+
+ // Postmatter
+ emitUndefs();
+}
+
+void TypeNodeEmitter::emitFallbackDefine(StringRef macroName,
+ StringRef fallbackMacroName,
+ StringRef args) {
+ Out << "#ifndef " << macroName << "\n";
+ Out << "# define " << macroName << args
+ << " " << fallbackMacroName << args << "\n";
+ Out << "#endif\n";
+
+ addMacroToUndef(macroName);
+}
+
+void TypeNodeEmitter::emitNodeInvocations() {
+ for (auto type : Types) {
+ // The name with the Type suffix.
+ StringRef id = getIdForType(type);
+
+ // Figure out which macro to use.
+ StringRef macroName;
+ auto setMacroName = [&](StringRef newName) {
+ if (!macroName.empty())
+ PrintFatalError(type->getLoc(),
+ Twine("conflict when computing macro name for "
+ "Type node: trying to use both \"")
+ + macroName + "\" and \"" + newName + "\"");
+ macroName = newName;
+ };
+ if (type->isSubClassOf(AlwaysDependentClassName))
+ setMacroName(DependentTypeMacroName);
+ if (type->isSubClassOf(NeverCanonicalClassName))
+ setMacroName(NonCanonicalTypeMacroName);
+ if (type->isSubClassOf(NeverCanonicalUnlessDependentClassName))
+ setMacroName(NonCanonicalUnlessDependentTypeMacroName);
+ if (type->getValueAsBit(AbstractFieldName))
+ setMacroName(AbstractTypeMacroName);
+ if (macroName.empty())
+ macroName = TypeMacroName;
+
+ // Compute the base class.
+ StringRef baseName = TypeClassName;
+ if (type->isSubClassOf(DerivedTypeClassName))
+ baseName = type->getValueAsDef(BaseFieldName)->getName();
+
+ // Generate the invocation line.
+ Out << macroName << "(" << id << ", " << baseName << ")\n";
+ }
+}
+
+void TypeNodeEmitter::emitLastNodeInvocation() {
+ // We check that this is non-empty earlier.
+ Out << "#ifdef " LastTypeMacroName "\n"
+ LastTypeMacroName "(" << getIdForType(Types.back()) << ")\n"
+ "#undef " LastTypeMacroName "\n"
+ "#endif\n";
+}
+
+void TypeNodeEmitter::emitLeafNodeInvocations() {
+ Out << "#ifdef " LeafTypeMacroName "\n";
+
+ for (auto type : Types) {
+ if (!type->isSubClassOf(LeafTypeClassName)) continue;
+ Out << LeafTypeMacroName "(" << getIdForType(type) << ")\n";
+ }
+
+ Out << "#undef " LeafTypeMacroName "\n"
+ "#endif\n";
+}
+
+void TypeNodeEmitter::addMacroToUndef(StringRef macroName) {
+ MacrosToUndef.push_back(macroName);
+}
+
+void TypeNodeEmitter::emitUndefs() {
+ for (auto &macroName : MacrosToUndef) {
+ Out << "#undef " << macroName << "\n";
+ }
+}
+
+void clang::EmitClangTypeNodes(RecordKeeper &records, raw_ostream &out) {
+ TypeNodeEmitter(records, out).emit();
+}
diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp
index 5cb688061dcb..9d668a281534 100644
--- a/utils/TableGen/NeonEmitter.cpp
+++ b/utils/TableGen/NeonEmitter.cpp
@@ -23,6 +23,7 @@
//
//===----------------------------------------------------------------------===//
+#include "TableGenBackends.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/None.h"
@@ -332,6 +333,17 @@ class Intrinsic {
NeonEmitter &Emitter;
std::stringstream OS;
+ bool isBigEndianSafe() const {
+ if (BigEndianSafe)
+ return true;
+
+ for (const auto &T : Types){
+ if (T.isVector() && T.getNumElements() > 1)
+ return false;
+ }
+ return true;
+ }
+
public:
Intrinsic(Record *R, StringRef Name, StringRef Proto, TypeSpec OutTS,
TypeSpec InTS, ClassKind CK, ListInit *Body, NeonEmitter &Emitter,
@@ -624,7 +636,7 @@ std::string Type::builtin_str() const {
default: llvm_unreachable("Unhandled case!");
}
- if (isChar() && !Pointer)
+ if (isChar() && !Pointer && Signed)
// Make chars explicitly signed.
S = "S" + S;
else if (isInteger() && !Pointer && !Signed)
@@ -1293,7 +1305,7 @@ void Intrinsic::emitReverseVariable(Variable &Dest, Variable &Src) {
}
void Intrinsic::emitArgumentReversal() {
- if (BigEndianSafe)
+ if (isBigEndianSafe())
return;
// Reverse all vector arguments.
@@ -1314,7 +1326,7 @@ void Intrinsic::emitArgumentReversal() {
}
void Intrinsic::emitReturnReversal() {
- if (BigEndianSafe)
+ if (isBigEndianSafe())
return;
if (!getReturnType().isVector() || getReturnType().isVoid() ||
getReturnType().getNumElements() == 1)
@@ -1401,7 +1413,7 @@ void Intrinsic::emitBodyAsBuiltinCall() {
if (T.getNumVectors() > 1) {
// Check if an explicit cast is needed.
std::string Cast;
- if (T.isChar() || T.isPoly() || !T.isSigned()) {
+ if (LocalCK == ClassB) {
Type T2 = T;
T2.makeOneVector();
T2.makeInteger(8, /*Signed=*/true);
@@ -1430,9 +1442,13 @@ void Intrinsic::emitBodyAsBuiltinCall() {
}
// Check if an explicit cast is needed.
- if (CastToType.isVector()) {
+ if (CastToType.isVector() &&
+ (LocalCK == ClassB || (T.isHalf() && !T.isScalarForMangling()))) {
CastToType.makeInteger(8, true);
Arg = "(" + CastToType.str() + ")" + Arg;
+ } else if (CastToType.isVector() && LocalCK == ClassI) {
+ CastToType.makeSigned();
+ Arg = "(" + CastToType.str() + ")" + Arg;
}
S += Arg + ", ";
@@ -1578,7 +1594,10 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagCall(DagInit *DI) {
Intr.Dependencies.insert(&Callee);
// Now create the call itself.
- std::string S = CallPrefix.str() + Callee.getMangledName(true) + "(";
+ std::string S = "";
+ if (!Callee.isBigEndianSafe())
+ S += CallPrefix.str();
+ S += Callee.getMangledName(true) + "(";
for (unsigned I = 0; I < DI->getNumArgs() - 1; ++I) {
if (I != 0)
S += ", ";
@@ -1732,12 +1751,12 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagShuffle(DagInit *DI){
SetTheory ST;
SetTheory::RecSet Elts;
- ST.addOperator("lowhalf", llvm::make_unique<LowHalf>());
- ST.addOperator("highhalf", llvm::make_unique<HighHalf>());
+ ST.addOperator("lowhalf", std::make_unique<LowHalf>());
+ ST.addOperator("highhalf", std::make_unique<HighHalf>());
ST.addOperator("rev",
- llvm::make_unique<Rev>(Arg1.first.getElementSizeInBits()));
+ std::make_unique<Rev>(Arg1.first.getElementSizeInBits()));
ST.addExpander("MaskExpand",
- llvm::make_unique<MaskExpander>(Arg1.first.getNumElements()));
+ std::make_unique<MaskExpander>(Arg1.first.getNumElements()));
ST.evaluate(DI->getArg(2), Elts, None);
std::string S = "__builtin_shufflevector(" + Arg1.second + ", " + Arg2.second;
@@ -1889,6 +1908,11 @@ Intrinsic::DagEmitter::emitDagArg(Init *Arg, std::string ArgName) {
}
std::string Intrinsic::generate() {
+ // Avoid duplicated code for big and little endian
+ if (isBigEndianSafe()) {
+ generateImpl(false, "", "");
+ return OS.str();
+ }
// Little endian intrinsics are simple and don't require any argument
// swapping.
OS << "#ifdef __LITTLE_ENDIAN__\n";
@@ -2456,7 +2480,7 @@ void NeonEmitter::run(raw_ostream &OS) {
for (auto *I : Defs)
I->indexBody();
- llvm::stable_sort(Defs, llvm::less_ptr<Intrinsic>());
+ llvm::stable_sort(Defs, llvm::deref<std::less<>>());
// Only emit a def when its requirements have been met.
// FIXME: This loop could be made faster, but it's fast enough for now.
@@ -2563,7 +2587,7 @@ void NeonEmitter::runFP16(raw_ostream &OS) {
for (auto *I : Defs)
I->indexBody();
- llvm::stable_sort(Defs, llvm::less_ptr<Intrinsic>());
+ llvm::stable_sort(Defs, llvm::deref<std::less<>>());
// Only emit a def when its requirements have been met.
// FIXME: This loop could be made faster, but it's fast enough for now.
@@ -2610,22 +2634,18 @@ void NeonEmitter::runFP16(raw_ostream &OS) {
OS << "#endif /* __ARM_FP16_H */\n";
}
-namespace clang {
-
-void EmitNeon(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitNeon(RecordKeeper &Records, raw_ostream &OS) {
NeonEmitter(Records).run(OS);
}
-void EmitFP16(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitFP16(RecordKeeper &Records, raw_ostream &OS) {
NeonEmitter(Records).runFP16(OS);
}
-void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) {
NeonEmitter(Records).runHeader(OS);
}
-void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) {
llvm_unreachable("Neon test generation no longer implemented!");
}
-
-} // end namespace clang
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index b9ec90fd5bcc..d0f8a7564496 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -47,6 +47,8 @@ enum ActionType {
GenClangCommentNodes,
GenClangDeclNodes,
GenClangStmtNodes,
+ GenClangTypeNodes,
+ GenClangOpcodes,
GenClangSACheckers,
GenClangCommentHTMLTags,
GenClangCommentHTMLTagsProperties,
@@ -129,6 +131,10 @@ cl::opt<ActionType> Action(
"Generate Clang AST declaration nodes"),
clEnumValN(GenClangStmtNodes, "gen-clang-stmt-nodes",
"Generate Clang AST statement nodes"),
+ clEnumValN(GenClangTypeNodes, "gen-clang-type-nodes",
+ "Generate Clang AST type nodes"),
+ clEnumValN(GenClangOpcodes, "gen-clang-opcodes",
+ "Generate Clang constexpr interpreter opcodes"),
clEnumValN(GenClangSACheckers, "gen-clang-sa-checkers",
"Generate Clang Static Analyzer checkers"),
clEnumValN(GenClangCommentHTMLTags, "gen-clang-comment-html-tags",
@@ -251,6 +257,12 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangStmtNodes:
EmitClangASTNodes(Records, OS, "Stmt", "");
break;
+ case GenClangTypeNodes:
+ EmitClangTypeNodes(Records, OS);
+ break;
+ case GenClangOpcodes:
+ EmitClangOpcodes(Records, OS);
+ break;
case GenClangSACheckers:
EmitClangSACheckers(Records, OS);
break;
diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h
index 02af66c5bf81..cdd492b4e558 100644
--- a/utils/TableGen/TableGenBackends.h
+++ b/utils/TableGen/TableGenBackends.h
@@ -27,6 +27,7 @@ namespace clang {
void EmitClangDeclContext(llvm::RecordKeeper &RK, llvm::raw_ostream &OS);
void EmitClangASTNodes(llvm::RecordKeeper &RK, llvm::raw_ostream &OS,
const std::string &N, const std::string &S);
+void EmitClangTypeNodes(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitClangAttrParserStringSwitches(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
@@ -77,6 +78,7 @@ void EmitClangCommentCommandInfo(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
void EmitClangCommentCommandList(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
+void EmitClangOpcodes(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitNeon(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitFP16(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);