aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-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/Extract/SourceExtraction.h51
-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
547 files changed, 37204 insertions, 14098 deletions
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/Extract/SourceExtraction.h b/lib/Tooling/Refactoring/Extract/SourceExtraction.h
deleted file mode 100644
index 545eb6c1a11c..000000000000
--- a/lib/Tooling/Refactoring/Extract/SourceExtraction.h
+++ /dev/null
@@ -1,51 +0,0 @@
-//===--- SourceExtraction.cpp - Clang refactoring library -----------------===//
-//
-// 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_TOOLING_REFACTORING_EXTRACT_SOURCE_EXTRACTION_H
-#define LLVM_CLANG_LIB_TOOLING_REFACTORING_EXTRACT_SOURCE_EXTRACTION_H
-
-#include "clang/Basic/LLVM.h"
-
-namespace clang {
-
-class LangOptions;
-class SourceManager;
-class SourceRange;
-class Stmt;
-
-namespace tooling {
-
-/// Determines which semicolons should be inserted during extraction.
-class ExtractionSemicolonPolicy {
-public:
- bool isNeededInExtractedFunction() const {
- return IsNeededInExtractedFunction;
- }
-
- bool isNeededInOriginalFunction() const { return IsNeededInOriginalFunction; }
-
- /// Returns the semicolon insertion policy that is needed for extraction of
- /// the given statement from the given source range.
- static ExtractionSemicolonPolicy compute(const Stmt *S,
- SourceRange &ExtractedRange,
- const SourceManager &SM,
- const LangOptions &LangOpts);
-
-private:
- ExtractionSemicolonPolicy(bool IsNeededInExtractedFunction,
- bool IsNeededInOriginalFunction)
- : IsNeededInExtractedFunction(IsNeededInExtractedFunction),
- IsNeededInOriginalFunction(IsNeededInOriginalFunction) {}
- bool IsNeededInExtractedFunction;
- bool IsNeededInOriginalFunction;
-};
-
-} // end namespace tooling
-} // end namespace clang
-
-#endif // LLVM_CLANG_LIB_TOOLING_REFACTORING_EXTRACT_SOURCE_EXTRACTION_H
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));
+}